/* Copyright (C) 2012-2018 Kentoku Shiba
   Copyright (c) 2020, 2022, MariaDB Corporation.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */

#define MYSQL_SERVER 1
#include <my_global.h>
#include "mysql_version.h"
#include "sql_priv.h"
#include "probes_mysql.h"
#include "sql_class.h"
#include "sql_partition.h"
#include "sql_analyse.h"
#include "sql_base.h"
#include "tztime.h"
#include "sql_select.h"
#include "sql_common.h"
#include <mysql.h>
#include <errmsg.h>
#include "spd_err.h"
#include "spd_param.h"
#include "spd_db_include.h"
#include "spd_include.h"
#include "spd_db_mysql.h"
#include "ha_spider.h"
#include "spd_conn.h"
#include "spd_db_conn.h"
#include "spd_malloc.h"
#include "spd_sys_table.h"
#include "spd_table.h"

extern struct charset_info_st *spd_charset_utf8mb3_bin;
extern bool volatile *spd_abort_loop;

extern handlerton *spider_hton_ptr;
extern pthread_mutex_t spider_open_conn_mutex;
extern HASH spider_open_connections;
extern HASH spider_ipport_conns;
extern SPIDER_DBTON spider_dbton[SPIDER_DBTON_SIZE];
extern const char spider_dig_upper[];
extern const char **spd_mysqld_unix_port;
extern uint *spd_mysqld_port;

spider_db_mysql_util spider_db_mysql_utility;
spider_db_mariadb_util spider_db_mariadb_utility;

#define SPIDER_SQL_NAME_QUOTE_STR "`"
#define SPIDER_SQL_NAME_QUOTE_LEN (sizeof(SPIDER_SQL_NAME_QUOTE_STR) - 1)
static const char *name_quote_str = SPIDER_SQL_NAME_QUOTE_STR;

#define SPIDER_SQL_ISO_READ_UNCOMMITTED_STR "set session transaction isolation level read uncommitted"
#define SPIDER_SQL_ISO_READ_UNCOMMITTED_LEN sizeof(SPIDER_SQL_ISO_READ_UNCOMMITTED_STR) - 1
#define SPIDER_SQL_ISO_READ_COMMITTED_STR "set session transaction isolation level read committed"
#define SPIDER_SQL_ISO_READ_COMMITTED_LEN sizeof(SPIDER_SQL_ISO_READ_COMMITTED_STR) - 1
#define SPIDER_SQL_ISO_REPEATABLE_READ_STR "set session transaction isolation level repeatable read"
#define SPIDER_SQL_ISO_REPEATABLE_READ_LEN sizeof(SPIDER_SQL_ISO_REPEATABLE_READ_STR) - 1
#define SPIDER_SQL_ISO_SERIALIZABLE_STR "set session transaction isolation level serializable"
#define SPIDER_SQL_ISO_SERIALIZABLE_LEN sizeof(SPIDER_SQL_ISO_SERIALIZABLE_STR) - 1

#define SPIDER_SQL_START_CONSISTENT_SNAPSHOT_STR "start transaction with consistent snapshot"
#define SPIDER_SQL_START_CONSISTENT_SNAPSHOT_LEN sizeof(SPIDER_SQL_START_CONSISTENT_SNAPSHOT_STR) - 1
#define SPIDER_SQL_START_TRANSACTION_STR "start transaction"
#define SPIDER_SQL_START_TRANSACTION_LEN sizeof(SPIDER_SQL_START_TRANSACTION_STR) - 1

#define SPIDER_SQL_AUTOCOMMIT_OFF_STR "set session autocommit = 0"
#define SPIDER_SQL_AUTOCOMMIT_OFF_LEN sizeof(SPIDER_SQL_AUTOCOMMIT_OFF_STR) - 1
#define SPIDER_SQL_AUTOCOMMIT_ON_STR "set session autocommit = 1"
#define SPIDER_SQL_AUTOCOMMIT_ON_LEN sizeof(SPIDER_SQL_AUTOCOMMIT_ON_STR) - 1

#define SPIDER_SQL_SQL_LOG_OFF_STR "set session sql_log_off = 0"
#define SPIDER_SQL_SQL_LOG_OFF_LEN sizeof(SPIDER_SQL_SQL_LOG_OFF_STR) - 1
#define SPIDER_SQL_SQL_LOG_ON_STR "set session sql_log_off = 1"
#define SPIDER_SQL_SQL_LOG_ON_LEN sizeof(SPIDER_SQL_SQL_LOG_ON_STR) - 1

#define SPIDER_SQL_WAIT_TIMEOUT_STR "set session wait_timeout = "
#define SPIDER_SQL_WAIT_TIMEOUT_LEN sizeof(SPIDER_SQL_WAIT_TIMEOUT_STR) - 1

#define SPIDER_SQL_SQL_MODE_STR "set session sql_mode = '"
#define SPIDER_SQL_SQL_MODE_LEN sizeof(SPIDER_SQL_SQL_MODE_STR) - 1

#define SPIDER_SQL_TIME_ZONE_STR "set session time_zone = '"
#define SPIDER_SQL_TIME_ZONE_LEN sizeof(SPIDER_SQL_TIME_ZONE_STR) - 1

#define SPIDER_SQL_SET_USER_VAL_STR "set @`"
#define SPIDER_SQL_SET_USER_VAL_LEN sizeof(SPIDER_SQL_SET_USER_VAL_STR) - 1

#define SPIDER_SQL_COMMIT_STR "commit"
#define SPIDER_SQL_COMMIT_LEN sizeof(SPIDER_SQL_COMMIT_STR) - 1
#define SPIDER_SQL_ROLLBACK_STR "rollback"
#define SPIDER_SQL_ROLLBACK_LEN sizeof(SPIDER_SQL_ROLLBACK_STR) - 1

#define SPIDER_SQL_XA_START_STR "xa start "
#define SPIDER_SQL_XA_START_LEN sizeof(SPIDER_SQL_XA_START_STR) - 1
#define SPIDER_SQL_XA_END_STR "xa end "
#define SPIDER_SQL_XA_END_LEN sizeof(SPIDER_SQL_XA_END_STR) - 1
#define SPIDER_SQL_XA_PREPARE_STR "xa prepare "
#define SPIDER_SQL_XA_PREPARE_LEN sizeof(SPIDER_SQL_XA_PREPARE_STR) - 1
#define SPIDER_SQL_XA_COMMIT_STR "xa commit "
#define SPIDER_SQL_XA_COMMIT_LEN sizeof(SPIDER_SQL_XA_COMMIT_STR) - 1
#define SPIDER_SQL_XA_ROLLBACK_STR "xa rollback "
#define SPIDER_SQL_XA_ROLLBACK_LEN sizeof(SPIDER_SQL_XA_ROLLBACK_STR) - 1

#define SPIDER_SQL_LOCK_TABLE_STR "lock tables "
#define SPIDER_SQL_LOCK_TABLE_LEN (sizeof(SPIDER_SQL_LOCK_TABLE_STR) - 1)
#define SPIDER_SQL_UNLOCK_TABLE_STR "unlock tables"
#define SPIDER_SQL_UNLOCK_TABLE_LEN (sizeof(SPIDER_SQL_UNLOCK_TABLE_STR) - 1)

#define SPIDER_SQL_LEFT_JOIN_STR " left join "
#define SPIDER_SQL_LEFT_JOIN_LEN (sizeof(SPIDER_SQL_LEFT_JOIN_STR) - 1)
#define SPIDER_SQL_RIGHT_JOIN_STR " right join "
#define SPIDER_SQL_RIGHT_JOIN_LEN (sizeof(SPIDER_SQL_RIGHT_JOIN_STR) - 1)
#define SPIDER_SQL_JOIN_STR " join "
#define SPIDER_SQL_JOIN_LEN (sizeof(SPIDER_SQL_JOIN_STR) - 1)
#define SPIDER_SQL_ON_STR " on "
#define SPIDER_SQL_ON_LEN (sizeof(SPIDER_SQL_ON_STR) - 1)

#define SPIDER_SQL_SHOW_TABLE_STATUS_STR "show table status from "
#define SPIDER_SQL_SHOW_TABLE_STATUS_LEN sizeof(SPIDER_SQL_SHOW_TABLE_STATUS_STR) - 1
#define SPIDER_SQL_SELECT_TABLES_STATUS_STR "select `table_rows`,`avg_row_length`,`data_length`,`max_data_length`,`index_length`,`auto_increment`,`create_time`,`update_time`,`check_time`,`checksum` from `information_schema`.`tables` where `table_schema` = "
#define SPIDER_SQL_SELECT_TABLES_STATUS_LEN sizeof(SPIDER_SQL_SELECT_TABLES_STATUS_STR) - 1
#define SPIDER_SQL_SHOW_WARNINGS_STR "show warnings"
#define SPIDER_SQL_SHOW_WARNINGS_LEN sizeof(SPIDER_SQL_SHOW_WARNINGS_STR) - 1

#define SPIDER_SQL_SHOW_MASTER_STATUS_STR "show master status"
#define SPIDER_SQL_SHOW_MASTER_STATUS_LEN sizeof(SPIDER_SQL_SHOW_MASTER_STATUS_STR) - 1
#define SPIDER_SQL_BINLOG_GTID_POS_STR "select binlog_gtid_pos"
#define SPIDER_SQL_BINLOG_GTID_POS_LEN sizeof(SPIDER_SQL_BINLOG_GTID_POS_STR) - 1

#define SPIDER_SQL_SHOW_COLUMNS_STR "show columns from "
#define SPIDER_SQL_SHOW_COLUMNS_LEN sizeof(SPIDER_SQL_SHOW_COLUMNS_STR) - 1
#define SPIDER_SQL_SELECT_COLUMNS_STR "select `column_name`,`column_default`,`is_nullable`,`character_set_name`,`collation_name`,`column_type`,`extra` from `information_schema`.`columns` where `table_schema` = "
#define SPIDER_SQL_SELECT_COLUMNS_LEN sizeof(SPIDER_SQL_SELECT_COLUMNS_STR) - 1

#define SPIDER_SQL_AUTO_INCREMENT_STR " auto_increment"
#define SPIDER_SQL_AUTO_INCREMENT_LEN sizeof(SPIDER_SQL_AUTO_INCREMENT_STR) - 1
#define SPIDER_SQL_ORDINAL_POSITION_STR "ordinal_position"
#define SPIDER_SQL_ORDINAL_POSITION_LEN sizeof(SPIDER_SQL_ORDINAL_POSITION_STR) - 1
#define SPIDER_SQL_FULLTEXT_STR "fulltext"
#define SPIDER_SQL_FULLTEXT_LEN sizeof(SPIDER_SQL_FULLTEXT_STR) - 1
#define SPIDER_SQL_SPATIAL_STR "spatial"
#define SPIDER_SQL_SPATIAL_LEN sizeof(SPIDER_SQL_SPATIAL_STR) - 1
#define SPIDER_SQL_USING_HASH_STR " using hash"
#define SPIDER_SQL_USING_HASH_LEN sizeof(SPIDER_SQL_USING_HASH_STR) - 1

#define SPIDER_SQL_SHOW_RECORDS_RECORDS_POS 0
#define SPIDER_SQL_EXPLAIN_SELECT_RECORDS_POS 8

#define SPIDER_SQL_CHECKSUM_CHECKSUM_POS 1
#define SPIDER_SQL_CHECKSUM_TABLE_STR "checksum table "
#define SPIDER_SQL_CHECKSUM_TABLE_LEN (sizeof(SPIDER_SQL_CHECKSUM_TABLE_STR) - 1)

#define SPIDER_SQL_LIKE_STR " like "
#define SPIDER_SQL_LIKE_LEN (sizeof(SPIDER_SQL_LIKE_STR) - 1)
#define SPIDER_SQL_LIMIT1_STR " limit 1"
#define SPIDER_SQL_LIMIT1_LEN (sizeof(SPIDER_SQL_LIMIT1_STR) - 1)
#define SPIDER_SQL_COLLATE_STR " collate "
#define SPIDER_SQL_COLLATE_LEN (sizeof(SPIDER_SQL_COLLATE_STR) - 1)

#define SPIDER_SQL_INTERVAL_STR " + interval "
#define SPIDER_SQL_INTERVAL_LEN (sizeof(SPIDER_SQL_INTERVAL_STR) - 1)
#define SPIDER_SQL_NEGINTERVAL_STR " - interval "
#define SPIDER_SQL_NEGINTERVAL_LEN (sizeof(SPIDER_SQL_NEGINTERVAL_STR) - 1)

static uchar SPIDER_SQL_LINESTRING_HEAD_STR[] =
  {0x00,0x00,0x00,0x00,0x01,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00};
#define SPIDER_SQL_LINESTRING_HEAD_LEN sizeof(SPIDER_SQL_LINESTRING_HEAD_STR)

#define SPIDER_SQL_DIRECT_INSERT_KIND_INSERT     0
#define SPIDER_SQL_DIRECT_INSERT_KIND_REPLACE    1
#define SPIDER_SQL_DIRECT_INSERT_KIND_IGNORE     2
#define SPIDER_SQL_DIRECT_INSERT_KIND_DUP_UPDATE 3

static const char *spider_db_table_lock_str[] =
{
  " read local,",
  " read,",
  " low_priority write,",
  " write,"
};
static const int spider_db_table_lock_len[] =
{
  sizeof(" read local,") - 1,
  sizeof(" read,") - 1,
  sizeof(" low_priority write,") - 1,
  sizeof(" write,") - 1
};
static const char *spider_db_timefunc_interval_str[] =
{
  " year", " quarter", " month", " week", " day",
  " hour", " minute", " second", " microsecond",
  " year_month", " day_hour", " day_minute",
  " day_second", " hour_minute", " hour_second",
  " minute_second", " day_microsecond", " hour_microsecond",
  " minute_microsecond", " second_microsecond"
};

/* UTC time zone for timestamp columns */
extern Time_zone *UTC;

int spider_mysql_init()
{
  DBUG_ENTER("spider_mysql_init");
  DBUG_RETURN(0);
}

int spider_mariadb_init()
{
  DBUG_ENTER("spider_mariadb_init");
  DBUG_RETURN(0);
}

int spider_mysql_deinit()
{
  DBUG_ENTER("spider_mysql_deinit");
  DBUG_RETURN(0);
}

int spider_mariadb_deinit()
{
  DBUG_ENTER("spider_mariadb_deinit");
  DBUG_RETURN(0);
}

spider_db_share *spider_mysql_create_share(
  SPIDER_SHARE *share
) {
  DBUG_ENTER("spider_mysql_create_share");
  DBUG_RETURN(new spider_mysql_share(share));
}

spider_db_share *spider_mariadb_create_share(
  SPIDER_SHARE *share
) {
  DBUG_ENTER("spider_mariadb_create_share");
  DBUG_RETURN(new spider_mariadb_share(share));
}

spider_db_handler *spider_mysql_create_handler(
  ha_spider *spider,
  spider_db_share *db_share
) {
  DBUG_ENTER("spider_mysql_create_handler");
  DBUG_RETURN(new spider_mysql_handler(spider,
    (spider_mbase_share *) db_share));
}

spider_db_handler *spider_mariadb_create_handler(
  ha_spider *spider,
  spider_db_share *db_share
) {
  DBUG_ENTER("spider_mariadb_create_handler");
  DBUG_RETURN(new spider_mariadb_handler(spider,
    (spider_mbase_share *) db_share));
}

spider_db_copy_table *spider_mysql_create_copy_table(
  spider_db_share *db_share
) {
  DBUG_ENTER("spider_mysql_create_copy_table");
  DBUG_RETURN(new spider_mysql_copy_table(
    (spider_mbase_share *) db_share));
}

spider_db_copy_table *spider_mariadb_create_copy_table(
  spider_db_share *db_share
) {
  DBUG_ENTER("spider_mariadb_create_copy_table");
  DBUG_RETURN(new spider_mariadb_copy_table(
    (spider_mbase_share *) db_share));
}

SPIDER_DB_CONN *spider_mysql_create_conn(
  SPIDER_CONN *conn
) {
  DBUG_ENTER("spider_mysql_create_conn");
  DBUG_RETURN(new spider_db_mysql(conn));
}

SPIDER_DB_CONN *spider_mariadb_create_conn(
  SPIDER_CONN *conn
) {
  DBUG_ENTER("spider_mariadb_create_conn");
  DBUG_RETURN(new spider_db_mariadb(conn));
}

bool spider_mysql_support_direct_join(
) {
  DBUG_ENTER("spider_mysql_support_direct_join");
  DBUG_RETURN(TRUE);
}

bool spider_mariadb_support_direct_join(
) {
  DBUG_ENTER("spider_mariadb_support_direct_join");
  DBUG_RETURN(TRUE);
}

/** Available `SPIDER_DBTON`s */
SPIDER_DBTON spider_dbton_mysql = {
  0,
  SPIDER_DB_WRAPPER_MYSQL,
  SPIDER_DB_ACCESS_TYPE_SQL,
  spider_mysql_init,
  spider_mysql_deinit,
  spider_mysql_create_share,
  spider_mysql_create_handler,
  spider_mysql_create_copy_table,
  spider_mysql_create_conn,
  spider_mysql_support_direct_join,
  &spider_db_mysql_utility,
  "For communication with MySQL using the native protocol",
  "3.4.0",
  SPIDER_MATURITY_STABLE
};

SPIDER_DBTON spider_dbton_mariadb = {
  0,
  SPIDER_DB_WRAPPER_MARIADB,
  SPIDER_DB_ACCESS_TYPE_SQL,
  spider_mariadb_init,
  spider_mariadb_deinit,
  spider_mariadb_create_share,
  spider_mariadb_create_handler,
  spider_mariadb_create_copy_table,
  spider_mariadb_create_conn,
  spider_mariadb_support_direct_join,
  &spider_db_mariadb_utility,
  "For communication with MariaDB using the native protocol",
  "3.4.0",
  SPIDER_MATURITY_STABLE
};

spider_db_mbase_row::spider_db_mbase_row(
  uint dbton_id
) : spider_db_row(dbton_id),
  row(NULL), lengths(NULL), cloned(FALSE)
{
  DBUG_ENTER("spider_db_mbase_row::spider_db_mbase_row");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mysql_row::spider_db_mysql_row() :
  spider_db_mbase_row(spider_db_mysql_utility.dbton_id)
{
  DBUG_ENTER("spider_db_mysql_row::spider_db_mysql_row");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mariadb_row::spider_db_mariadb_row() :
  spider_db_mbase_row(spider_db_mariadb_utility.dbton_id)
{
  DBUG_ENTER("spider_db_mariadb_row::spider_db_mariadb_row");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mbase_row::~spider_db_mbase_row()
{
  DBUG_ENTER("spider_db_mbase_row::~spider_db_mbase_row");
  DBUG_PRINT("info",("spider this=%p", this));
  if (cloned)
  {
    spider_free(spider_current_trx, row_first, MYF(0));
  }
  DBUG_VOID_RETURN;
}

spider_db_mysql_row::~spider_db_mysql_row()
{
  DBUG_ENTER("spider_db_mysql_row::~spider_db_mysql_row");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mariadb_row::~spider_db_mariadb_row()
{
  DBUG_ENTER("spider_db_mariadb_row::~spider_db_mariadb_row");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

int spider_db_mbase_row::store_to_field(
  Field *field,
  CHARSET_INFO *access_charset
) {
  DBUG_ENTER("spider_db_mbase_row::store_to_field");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!*row)
  {
    DBUG_PRINT("info", ("spider field is null"));
    field->set_null();
    field->reset();
  } else {
    field->set_notnull();
    if (field->flags & BLOB_FLAG)
    {
      DBUG_PRINT("info", ("spider blob field"));
      if (
        field->charset() == &my_charset_bin ||
        field->charset()->cset == access_charset->cset
      )
        ((Field_blob *)field)->set_ptr(*lengths, (uchar *) *row);
      else {
        DBUG_PRINT("info", ("spider blob convert"));
        if (field->table->file->ht == spider_hton_ptr)
        {
          ha_spider *spider = (ha_spider *) field->table->file;
          spider_string *str = &spider->blob_buff[field->field_index];
          str->length(0);
          if (str->append(*row, *lengths, access_charset))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          ((Field_blob *)field)->set_ptr(str->length(), (uchar *) str->ptr());
        } else {
          field->store(*row, *lengths, access_charset);
        }
      }
    } else
      field->store(*row, *lengths, access_charset);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_row::append_to_str(
  spider_string *str
) {
  DBUG_ENTER("spider_db_mbase_row::append_to_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(*lengths))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(*row, *lengths);
  DBUG_RETURN(0);
}

int spider_db_mbase_row::append_escaped_to_str(
  spider_string *str,
  uint dbton_id
) {
  DBUG_ENTER("spider_db_mbase_row::append_escaped_to_str");
  DBUG_PRINT("info",("spider this=%p", this));
  spider_string tmp_str(*row, *lengths + 1, str->charset());
  tmp_str.init_calc_mem(SPD_MID_DB_MBASE_ROW_APPEND_ESCAPED_TO_STR_1);
  tmp_str.length(*lengths);
  if (str->reserve(*lengths * 2 + 2))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  spider_dbton[dbton_id].db_util->append_escaped_util(str, tmp_str.get_str());
  DBUG_RETURN(0);
}

void spider_db_mbase_row::first()
{
  DBUG_ENTER("spider_db_mbase_row::first");
  DBUG_PRINT("info",("spider this=%p", this));
  row = row_first;
  lengths = lengths_first;
  DBUG_VOID_RETURN;
}

void spider_db_mbase_row::next()
{
  DBUG_ENTER("spider_db_mbase_row::next");
  DBUG_PRINT("info",("spider this=%p", this));
  row++;
  lengths++;
  DBUG_VOID_RETURN;
}

bool spider_db_mbase_row::is_null()
{
  DBUG_ENTER("spider_db_mbase_row::is_null");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(!(*row));
}

int spider_db_mbase_row::val_int()
{
  DBUG_ENTER("spider_db_mbase_row::val_int");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(*row ? atoi(*row) : 0);
}

double spider_db_mbase_row::val_real()
{
  DBUG_ENTER("spider_db_mbase_row::val_real");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(*row ? my_atof(*row) : 0.0);
}

my_decimal *spider_db_mbase_row::val_decimal(
  my_decimal *decimal_value,
  CHARSET_INFO *access_charset
) {
  DBUG_ENTER("spider_db_mbase_row::val_decimal");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!*row)
    DBUG_RETURN(NULL);

#ifdef SPIDER_HAS_DECIMAL_OPERATION_RESULTS_VALUE_TYPE
  decimal_operation_results(str2my_decimal(0, *row, *lengths, access_charset,
    decimal_value), "", "");
#else
  decimal_operation_results(str2my_decimal(0, *row, *lengths, access_charset,
    decimal_value));
#endif

  DBUG_RETURN(decimal_value);
}

SPIDER_DB_ROW *spider_db_mbase_row::clone()
{
  spider_db_mbase_row *clone_row;
  char *tmp_char;
  MYSQL_ROW tmp_row = row_first, ctmp_row;
  ulong *tmp_lengths = lengths_first;
  uint row_size, i;
  DBUG_ENTER("spider_db_mbase_row::clone");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(clone_row = new spider_db_mbase_row(dbton_id)))
  {
    DBUG_RETURN(NULL);
  }
  if (!record_size)
  {
    row_size = field_count;
    for (i = 0; i < field_count; i++)
    {
      row_size += *tmp_lengths;
      tmp_lengths++;
    }
    record_size = row_size - field_count;
  } else {
    row_size = record_size + field_count;
  }
  if (!spider_bulk_malloc(
        spider_current_trx,  SPD_MID_DB_MBASE_ROW_CLONE_1, MYF(MY_WME),
        &clone_row->row, (uint) (sizeof(char*) * (field_count + 1)),
        &tmp_char, (uint) (row_size),
        &clone_row->lengths, (uint) (sizeof(ulong) * field_count),
        NullS)
  ) {
    delete clone_row;
    DBUG_RETURN(NULL);
  }
  memcpy(clone_row->lengths, lengths_first, sizeof(ulong) * field_count);
  tmp_lengths = lengths_first;
  ctmp_row = clone_row->row;
  for (i = 0; i < field_count; i++)
  {
    DBUG_PRINT("info",("spider *lengths=%lu", *tmp_lengths));
    if (*tmp_row == NULL)
    {
      *ctmp_row = NULL;
      *tmp_char = 0;
      tmp_char++;
    } else {
      *ctmp_row = tmp_char;
      memcpy(tmp_char, *tmp_row, *tmp_lengths + 1);
      tmp_char += *tmp_lengths + 1;
    }
    ctmp_row++;
    tmp_lengths++;
    tmp_row++;
  }
  clone_row->row[field_count] = NULL;
  clone_row->field_count = field_count;
  clone_row->record_size = record_size;
  clone_row->row_first = clone_row->row;
  clone_row->lengths_first = clone_row->lengths;
  clone_row->cloned = TRUE;
  DBUG_RETURN((SPIDER_DB_ROW *) clone_row);
}

int spider_db_mbase_row::store_to_tmp_table(
  TABLE *tmp_table,
  spider_string *str
) {
  uint i;
  MYSQL_ROW tmp_row = row;
  ulong *tmp_lengths = lengths;
  DBUG_ENTER("spider_db_mbase_row::store_to_tmp_table");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(0);
  for (i = 0; i < field_count; i++)
  {
    if (*tmp_row)
    {
      if (str->reserve(*tmp_lengths + 1))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(*tmp_row, *tmp_lengths + 1);
    }
    tmp_lengths++;
    tmp_row++;
  }
  tmp_table->field[0]->set_notnull();
  tmp_table->field[0]->store(
    (const char *) lengths,
    sizeof(ulong) * field_count, &my_charset_bin);
  tmp_table->field[1]->set_notnull();
  tmp_table->field[1]->store(
    str->ptr(), str->length(), &my_charset_bin);
  tmp_table->field[2]->set_notnull();
  tmp_table->field[2]->store(
    (char *) row, (uint) (sizeof(char *) * field_count), &my_charset_bin);
  DBUG_RETURN(tmp_table->file->ha_write_row(tmp_table->record[0]));
}

uint spider_db_mbase_row::get_byte_size()
{
  ulong *tmp_lengths = lengths_first;
  uint i;
  DBUG_ENTER("spider_db_mbase_row::get_byte_size");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!record_size)
  {
    for (i = 0; i < field_count; i++)
    {
      record_size += *tmp_lengths;
      tmp_lengths++;
    }
  }
  DBUG_RETURN(record_size);
}

spider_db_mbase_result::spider_db_mbase_result(
  SPIDER_DB_CONN *in_db_conn
) : spider_db_result(in_db_conn),
  db_result(NULL), row(in_db_conn->dbton_id)
{
  DBUG_ENTER("spider_db_mbase_result::spider_db_mbase_result");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mysql_result::spider_db_mysql_result(
  SPIDER_DB_CONN *in_db_conn
) : spider_db_mbase_result(in_db_conn)
{
  DBUG_ENTER("spider_db_mysql_result::spider_db_mysql_result");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mariadb_result::spider_db_mariadb_result(
  SPIDER_DB_CONN *in_db_conn
) : spider_db_mbase_result(in_db_conn)
{
  DBUG_ENTER("spider_db_mariadb_result::spider_db_mariadb_result");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mbase_result::~spider_db_mbase_result()
{
  DBUG_ENTER("spider_db_mbase_result::~spider_db_mbase_result");
  DBUG_PRINT("info",("spider this=%p", this));
  if (db_result)
  {
    free_result();
  }
  DBUG_VOID_RETURN;
}

spider_db_mysql_result::~spider_db_mysql_result()
{
  DBUG_ENTER("spider_db_mysql_result::~spider_db_mysql_result");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mariadb_result::~spider_db_mariadb_result()
{
  DBUG_ENTER("spider_db_mariadb_result::~spider_db_mariadb_result");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

bool spider_db_mbase_result::has_result()
{
  DBUG_ENTER("spider_db_mbase_result::has_result");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(db_result);
}

void spider_db_mbase_result::free_result()
{
  DBUG_ENTER("spider_db_mbase_result::free_result");
  DBUG_PRINT("info",("spider this=%p", this));
  /* need 2 times execution design */
  if (db_result)
  {
    mysql_free_result(db_result);
    db_result = NULL;
  }
  DBUG_VOID_RETURN;
}

SPIDER_DB_ROW *spider_db_mbase_result::current_row()
{
  DBUG_ENTER("spider_db_mbase_result::current_row");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN((SPIDER_DB_ROW *) row.clone());
}

/*
  Fetch results from the data node and store them in a
  SPIDER_DB_ROW

  @param  skips   A bitmap specifying which fields to skip storing
*/
SPIDER_DB_ROW *spider_db_mbase_result::fetch_row(MY_BITMAP *skips)
{
  DBUG_ENTER("spider_db_mbase_result::fetch_row");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(row.row = mysql_fetch_row(db_result)))
  {
    if (mysql_errno(((spider_db_mbase *) db_conn)->db_conn))
    {
      store_error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn);
      my_message(store_error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
    } else
      store_error_num = HA_ERR_END_OF_FILE;
    DBUG_RETURN(NULL);
  }
  row.lengths = mysql_fetch_lengths(db_result);
  if (skips != NULL)
  {
    uint i= 0;
    for (uint j= 0; j < mysql_num_fields(db_result); j++)
    {
      if (!bitmap_is_set(skips, j))
      {
        row.row[i]= row.row[j];
        row.lengths[i]= row.lengths[j];
        i++;
      }
    }
    row.field_count= i;
  }
  else
    row.field_count = mysql_num_fields(db_result);
  row.row[row.field_count] = NULL;
  row.row_first = row.row;
  row.lengths_first = row.lengths;
  row.record_size = 0;
  DBUG_RETURN((SPIDER_DB_ROW *) &row);
}

SPIDER_DB_ROW *spider_db_mbase_result::fetch_row_from_tmp_table(
  TABLE *tmp_table
) {
  uint i;
  spider_string tmp_str1, tmp_str2, tmp_str3;
  const char *row_ptr;
  MYSQL_ROW tmp_row;
  ulong *tmp_lengths;
  uint field_count;
  DBUG_ENTER("spider_db_mbase_result::fetch_row_from_tmp_table");
  DBUG_PRINT("info",("spider this=%p", this));
  tmp_str1.init_calc_mem(SPD_MID_DB_MBASE_RESULT_FETCH_ROW_FROM_TMP_TABLE_1);
  tmp_str2.init_calc_mem(SPD_MID_DB_MBASE_RESULT_FETCH_ROW_FROM_TMP_TABLE_2);
  tmp_str3.init_calc_mem(SPD_MID_DB_MBASE_RESULT_FETCH_ROW_FROM_TMP_TABLE_3);
  tmp_table->field[0]->val_str(tmp_str1.get_str());
  tmp_table->field[1]->val_str(tmp_str2.get_str());
  tmp_table->field[2]->val_str(tmp_str3.get_str());
  tmp_str1.mem_calc();
  tmp_str2.mem_calc();
  tmp_str3.mem_calc();
  row_ptr = tmp_str2.ptr();
  tmp_lengths = (ulong *) tmp_str1.ptr();
  tmp_row = (MYSQL_ROW) tmp_str3.ptr();
  field_count = tmp_str1.length() / sizeof(ulong);
  row.row = tmp_row;
  row.lengths = tmp_lengths;
  row.field_count = field_count;
  row.row_first = row.row;
  row.lengths_first = row.lengths;
  row.record_size = tmp_str2.length();
  for (i = 0; i < field_count; i++)
  {
    if (*tmp_row)
    {
      *tmp_row = (char *) row_ptr;
      row_ptr += *tmp_lengths + 1;
    }
    tmp_row++;
    tmp_lengths++;
  }
  DBUG_RETURN((SPIDER_DB_ROW *) &row);
}

/* Fetches table status into `stat` */
int spider_db_mbase_result::fetch_table_status(
  int mode,
  ha_statistics &stat
) {
  int error_num;
  MYSQL_ROW mysql_row;
  MYSQL_TIME mysql_time;
  uint not_used_uint;
#ifdef SPIDER_HAS_TIME_STATUS
  MYSQL_TIME_STATUS time_status;
#else
  int time_status;
#endif
  long not_used_long;
  DBUG_ENTER("spider_db_mbase_result::fetch_table_status");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    DBUG_RETURN(ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM);
  }
  if (mode == 1)
  {
    /* Ok to test for 18 fields as all new fields are added last */
    if (num_fields() < 18)
    {
      DBUG_PRINT("info",("spider field_count < 18"));
      DBUG_RETURN(ER_SPIDER_INVALID_REMOTE_TABLE_INFO_NUM);
    }

    if (mysql_row[4])
      stat.records =
        (ha_rows) my_strtoll10(mysql_row[4], (char**) NULL, &error_num);
    else
      stat.records = (ha_rows) 0;
    DBUG_PRINT("info",
      ("spider records=%lld", stat.records));
    if (mysql_row[5])
      stat.mean_rec_length =
        (ulong) my_strtoll10(mysql_row[5], (char**) NULL, &error_num);
    else
      stat.mean_rec_length = 0;
    DBUG_PRINT("info",
      ("spider mean_rec_length=%lu", stat.mean_rec_length));
    if (mysql_row[6])
      stat.data_file_length =
        (ulonglong) my_strtoll10(mysql_row[6], (char**) NULL, &error_num);
    else
      stat.data_file_length = 0;
    DBUG_PRINT("info",
      ("spider data_file_length=%lld", stat.data_file_length));
    if (mysql_row[7])
      stat.max_data_file_length =
        (ulonglong) my_strtoll10(mysql_row[7], (char**) NULL, &error_num);
    else
      stat.max_data_file_length = 0;
    DBUG_PRINT("info",
      ("spider max_data_file_length=%lld", stat.max_data_file_length));
    if (mysql_row[8])
      stat.index_file_length =
        (ulonglong) my_strtoll10(mysql_row[8], (char**) NULL, &error_num);
    else
      stat.index_file_length = 0;
    DBUG_PRINT("info",
      ("spider index_file_length=%lld", stat.index_file_length));
    if (mysql_row[10])
      stat.auto_increment_value =
        (ulonglong) my_strtoll10(mysql_row[10], (char**) NULL, &error_num);
    else
      stat.auto_increment_value = 1;
    DBUG_PRINT("info",
      ("spider auto_increment_value=%lld", stat.auto_increment_value));
    if (mysql_row[11])
    {
#ifdef SPIDER_HAS_TIME_STATUS
      my_time_status_init(&time_status);
#endif
      SPIDER_str_to_datetime(mysql_row[11], strlen(mysql_row[11]),
        &mysql_time, 0, &time_status);
      stat.create_time = (time_t) my_system_gmt_sec(&mysql_time,
        &not_used_long, &not_used_uint);
    } else
      stat.create_time = (time_t) 0;
#ifdef DBUG_TRACE
    {
      struct tm *ts, tmp_ts;
      char buf[80];
      ts = localtime_r(&stat.create_time, &tmp_ts);
      strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ts);
      DBUG_PRINT("info",("spider create_time=%s", buf));
    }
#endif
    if (mysql_row[12])
    {
#ifdef SPIDER_HAS_TIME_STATUS
      my_time_status_init(&time_status);
#endif
      SPIDER_str_to_datetime(mysql_row[12], strlen(mysql_row[12]),
        &mysql_time, 0, &time_status);
      stat.update_time = (time_t) my_system_gmt_sec(&mysql_time,
        &not_used_long, &not_used_uint);
    } else
      stat.update_time = (time_t) 0;
#ifndef DBUG_OFF
    {
      struct tm *ts, tmp_ts;
      char buf[80];
      ts = localtime_r(&stat.update_time, &tmp_ts);
      strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ts);
      DBUG_PRINT("info",("spider update_time=%s", buf));
    }
#endif
    if (mysql_row[13])
    {
#ifdef SPIDER_HAS_TIME_STATUS
      my_time_status_init(&time_status);
#endif
      SPIDER_str_to_datetime(mysql_row[13], strlen(mysql_row[13]),
        &mysql_time, 0, &time_status);
      stat.check_time = (time_t) my_system_gmt_sec(&mysql_time,
        &not_used_long, &not_used_uint);
    } else
      stat.check_time = (time_t) 0;
#ifdef DBUG_TRACE
    {
      struct tm *ts, tmp_ts;
      char buf[80];
      ts = localtime_r(&stat.check_time, &tmp_ts);
      strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ts);
      DBUG_PRINT("info",("spider check_time=%s", buf));
    }
#endif
    if (mysql_row[15])
    {
      stat.checksum_null = FALSE;
      stat.checksum =
        (ha_checksum) my_strtoll10(mysql_row[15], (char**) NULL, &error_num);
      DBUG_PRINT("info", ("spider checksum=%lu", (ulong) stat.checksum));
    } else {
      stat.checksum_null = TRUE;
      stat.checksum = (ha_checksum) 0;
      DBUG_PRINT("info", ("spider checksum is null"));
    }
  } else {
    if (mysql_row[0])
      stat.records =
        (ha_rows) my_strtoll10(mysql_row[0], (char**) NULL, &error_num);
    else
      stat.records = (ha_rows) 0;
    DBUG_PRINT("info",
      ("spider records=%lld", stat.records));
    if (mysql_row[1])
      stat.mean_rec_length =
        (ulong) my_strtoll10(mysql_row[1], (char**) NULL, &error_num);
    else
      stat.mean_rec_length = 0;
    DBUG_PRINT("info",
      ("spider mean_rec_length=%lu", stat.mean_rec_length));
    if (mysql_row[2])
      stat.data_file_length =
        (ulonglong) my_strtoll10(mysql_row[2], (char**) NULL, &error_num);
    else
      stat.data_file_length = 0;
    DBUG_PRINT("info",
      ("spider data_file_length=%lld", stat.data_file_length));
    if (mysql_row[3])
      stat.max_data_file_length =
        (ulonglong) my_strtoll10(mysql_row[3], (char**) NULL, &error_num);
    else
      stat.max_data_file_length = 0;
    DBUG_PRINT("info",
      ("spider max_data_file_length=%lld", stat.max_data_file_length));
    if (mysql_row[4])
      stat.index_file_length =
        (ulonglong) my_strtoll10(mysql_row[4], (char**) NULL, &error_num);
    else
      stat.index_file_length = 0;
    DBUG_PRINT("info",
      ("spider index_file_length=%lld", stat.index_file_length));
    if (mysql_row[5])
      stat.auto_increment_value =
        (ulonglong) my_strtoll10(mysql_row[5], (char**) NULL, &error_num);
    else
      stat.auto_increment_value = 1;
    DBUG_PRINT("info",
      ("spider auto_increment_value=%lld", stat.auto_increment_value));
    if (mysql_row[6])
    {
#ifdef SPIDER_HAS_TIME_STATUS
      my_time_status_init(&time_status);
#endif
      SPIDER_str_to_datetime(mysql_row[6], strlen(mysql_row[6]),
        &mysql_time, 0, &time_status);
      stat.create_time = (time_t) my_system_gmt_sec(&mysql_time,
        &not_used_long, &not_used_uint);
    } else
      stat.create_time = (time_t) 0;
#ifdef DBUG_TRACE
    {
      struct tm *ts, tmp_ts;
      char buf[80];
      ts = localtime_r(&stat.create_time, &tmp_ts);
      strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ts);
      DBUG_PRINT("info",("spider create_time=%s", buf));
    }
#endif
    if (mysql_row[7])
    {
#ifdef SPIDER_HAS_TIME_STATUS
      my_time_status_init(&time_status);
#endif
      SPIDER_str_to_datetime(mysql_row[7], strlen(mysql_row[7]),
        &mysql_time, 0, &time_status);
      stat.update_time = (time_t) my_system_gmt_sec(&mysql_time,
        &not_used_long, &not_used_uint);
    } else
      stat.update_time = (time_t) 0;
#ifdef DBUG_TRACE
    {
      struct tm *ts, tmp_ts;
      char buf[80];
      ts = localtime_r(&stat.update_time, &tmp_ts);
      strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ts);
      DBUG_PRINT("info",("spider update_time=%s", buf));
    }
#endif
    if (mysql_row[8])
    {
#ifdef SPIDER_HAS_TIME_STATUS
      my_time_status_init(&time_status);
#endif
      SPIDER_str_to_datetime(mysql_row[8], strlen(mysql_row[8]),
        &mysql_time, 0, &time_status);
      stat.check_time = (time_t) my_system_gmt_sec(&mysql_time,
        &not_used_long, &not_used_uint);
    } else
      stat.check_time = (time_t) 0;
#ifdef DBUG_TRACE
    {
      struct tm *ts, tmp_ts;
      char buf[80];
      ts = localtime_r(&stat.check_time, &tmp_ts);
      strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ts);
      DBUG_PRINT("info",("spider check_time=%s", buf));
    }
#endif
    if (mysql_row[9])
    {
      stat.checksum_null = FALSE;
      stat.checksum =
        (ha_checksum) my_strtoll10(mysql_row[9], (char**) NULL, &error_num);
      DBUG_PRINT("info", ("spider checksum=%lu", (ulong) stat.checksum));
    } else {
      stat.checksum_null = TRUE;
      stat.checksum = (ha_checksum) 0;
      DBUG_PRINT("info", ("spider checksum is null"));
    }
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_result::fetch_simple_action(
  uint simple_action,
  uint position,
  void *param
) {
  int error_num;
  MYSQL_ROW mysql_row;
  DBUG_ENTER("spider_db_mbase_result::fetch_simple_action");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    DBUG_RETURN(ER_QUERY_ON_FOREIGN_DATA_SOURCE);
  }
  if (num_fields() <= position)
  {
    DBUG_RETURN(ER_QUERY_ON_FOREIGN_DATA_SOURCE);
  }
  switch (simple_action)
  {
    case SPIDER_SIMPLE_RECORDS:
    {
      ha_rows *records = (ha_rows *) param;
      if (mysql_row[position])
      {
        *records =
          (ha_rows) my_strtoll10(mysql_row[position], (char**) NULL,
          &error_num);
      } else {
        *records = (ha_rows) 0;
      }
      DBUG_PRINT("info", ("spider records=%lld", *records));
      break;
    }
    case SPIDER_SIMPLE_CHECKSUM_TABLE:
    {
      ha_spider *spider = (ha_spider *) param;
      if (mysql_row[position])
      {
        spider->checksum_val =
          (ha_checksum) my_strtoll10(mysql_row[position], (char**) NULL,
          &error_num);
        DBUG_PRINT("info", ("spider checksum=%llu", (ulonglong)spider->checksum_val));
        spider->checksum_null = FALSE;
      } else {
        spider->checksum_null = TRUE;
        DBUG_PRINT("info", ("spider checksum is null"));
      }
      break;
    }
    default:
      DBUG_ASSERT(0);
      break;
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_result::fetch_table_records(
  int mode,
  ha_rows &records
) {
  DBUG_ENTER("spider_db_mbase_result::fetch_table_records");
  DBUG_PRINT("info",("spider this=%p", this));
  if (mode == 1)
  {
    DBUG_RETURN(fetch_simple_action(SPIDER_SIMPLE_RECORDS,
      SPIDER_SQL_SHOW_RECORDS_RECORDS_POS, &records));
  } else {
    DBUG_RETURN(fetch_simple_action(SPIDER_SIMPLE_RECORDS,
      SPIDER_SQL_EXPLAIN_SELECT_RECORDS_POS, &records));
  }
}

int spider_db_mbase_result::fetch_table_checksum(
  ha_spider *spider
) {
  DBUG_ENTER("spider_db_mbase_result::fetch_table_checksum");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(fetch_simple_action(SPIDER_SIMPLE_CHECKSUM_TABLE,
    SPIDER_SQL_CHECKSUM_CHECKSUM_POS, spider));
}

int spider_db_mbase_result::fetch_table_cardinality(
  int mode,
  TABLE *table,
  longlong *cardinality,
  uchar *cardinality_upd,
  int bitmap_size
) {
  int error_num;
  MYSQL_ROW mysql_row;
  Field *field;
  DBUG_ENTER("spider_db_mbase_result::fetch_table_cardinality");
  DBUG_PRINT("info",("spider this=%p", this));
  memset((uchar *) cardinality_upd, 0, sizeof(uchar) * bitmap_size);
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    /* no index */
    DBUG_RETURN(0);
  }
  if (mode == 1)
  {
    uint num_fields = this->num_fields();
    if (num_fields < 12 || num_fields > 14)
    {
      DBUG_PRINT("info",("spider num_fields < 12 || num_fields > 14"));
      DBUG_RETURN(ER_SPIDER_INVALID_REMOTE_TABLE_INFO_NUM);
    }

    while (mysql_row)
    {
      if (
        mysql_row[4] &&
        mysql_row[6] &&
        (field = find_field_in_table_sef(table,
                                         Lex_cstring_strlen(mysql_row[4])))
      ) {
        if ((cardinality[field->field_index] =
          (longlong) my_strtoll10(mysql_row[6], (char**) NULL, &error_num))
        <= 0)
          cardinality[field->field_index] = 1;
        spider_set_bit(cardinality_upd, field->field_index);
        DBUG_PRINT("info",
          ("spider col_name=%s", mysql_row[4]));
        DBUG_PRINT("info",
          ("spider cardinality=%lld",
          cardinality[field->field_index]));
      } else if (mysql_row[4])
      {
        DBUG_PRINT("info",
          ("spider skip col_name=%s", mysql_row[4]));
      } else {
        DBUG_RETURN(ER_SPIDER_INVALID_REMOTE_TABLE_INFO_NUM);
      }
      mysql_row = mysql_fetch_row(db_result);
    }
  } else {
    while (mysql_row)
    {
      if (
        mysql_row[0] &&
        mysql_row[1] &&
        (field = find_field_in_table_sef(table,
                                         Lex_cstring_strlen(mysql_row[0])))
      ) {
        if ((cardinality[field->field_index] =
          (longlong) my_strtoll10(mysql_row[1], (char**) NULL, &error_num))
        <= 0)
          cardinality[field->field_index] = 1;
        spider_set_bit(cardinality_upd, field->field_index);
        DBUG_PRINT("info",
          ("spider col_name=%s", mysql_row[0]));
        DBUG_PRINT("info",
          ("spider cardinality=%lld",
          cardinality[field->field_index]));
      } else if (mysql_row[0])
      {
        DBUG_PRINT("info",
          ("spider skip col_name=%s", mysql_row[0]));
      } else {
        DBUG_RETURN(ER_SPIDER_INVALID_REMOTE_TABLE_INFO_NUM);
      }
      mysql_row = mysql_fetch_row(db_result);
    }
  }
  if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
  {
    my_message(error_num,
      mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_result::fetch_table_mon_status(
  int &status
) {
  int error_num;
  MYSQL_ROW mysql_row;
  DBUG_ENTER("spider_db_mbase_result::fetch_table_mon_status");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  if (num_fields() != 1)
  {
    DBUG_PRINT("info",("spider num_fields != 1"));
    my_printf_error(ER_SPIDER_UNKNOWN_NUM, ER_SPIDER_UNKNOWN_STR, MYF(0));
    DBUG_RETURN(ER_SPIDER_UNKNOWN_NUM);
  }
  if (mysql_row[0])
    status = atoi(mysql_row[0]);
  else
    status = SPIDER_LINK_MON_OK;
  DBUG_PRINT("info", ("spider status=%d", status));
  DBUG_RETURN(0);
}

int spider_db_mbase_result::fetch_show_master_status(
  const char **binlog_file_name,
  const char **binlog_pos
) {
  int error_num;
  MYSQL_ROW mysql_row;
  DBUG_ENTER("spider_db_mbase_result::fetch_show_master_status");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    DBUG_RETURN(ER_QUERY_ON_FOREIGN_DATA_SOURCE);
  }
  if (num_fields() != 4)
  {
    DBUG_RETURN(ER_QUERY_ON_FOREIGN_DATA_SOURCE);
  }

  *binlog_file_name = mysql_row[0];
  DBUG_PRINT("info",("spider binlog_file_name=%s", *binlog_file_name));
  *binlog_pos = mysql_row[1];
  DBUG_PRINT("info",("spider binlog_pos=%s", *binlog_pos));
  DBUG_RETURN(0);
}

int spider_db_mbase_result::fetch_select_binlog_gtid_pos(
  const char **gtid_pos
) {
  int error_num;
  MYSQL_ROW mysql_row;
  DBUG_ENTER("spider_db_mbase_result::fetch_select_binlog_gtid_pos");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    DBUG_RETURN(ER_QUERY_ON_FOREIGN_DATA_SOURCE);
  }
  if (num_fields() != 1)
  {
    DBUG_RETURN(ER_QUERY_ON_FOREIGN_DATA_SOURCE);
  }

  *gtid_pos = mysql_row[0];
  DBUG_PRINT("info",("spider gtid_pos=%s", *gtid_pos));
  DBUG_RETURN(0);
}

longlong spider_db_mbase_result::num_rows()
{
  DBUG_ENTER("spider_db_mbase_result::num_rows");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN((longlong) mysql_num_rows(db_result));
}

uint spider_db_mbase_result::num_fields()
{
  DBUG_ENTER("spider_db_mbase_result::num_fields");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(mysql_num_fields(db_result));
}

void spider_db_mbase_result::move_to_pos(
  longlong pos
) {
  DBUG_ENTER("spider_db_mbase_result::move_to_pos");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider pos=%lld", pos));
/*
  DBUG_ASSERT(first_row);
*/
  db_result->data_cursor = first_row + pos;
  DBUG_VOID_RETURN;
}

int spider_db_mbase_result::get_errno()
{
  DBUG_ENTER("spider_db_mbase_result::get_errno");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider store_error_num=%d", store_error_num));
  DBUG_RETURN(store_error_num);
}

int spider_db_mbase_result::fetch_columns_for_discover_table_structure(
  spider_string *str,
  CHARSET_INFO *access_charset
) {
  int error_num;
  uint length;
  MYSQL_ROW mysql_row;
  DBUG_ENTER("spider_db_mbase_result::fetch_columns_for_discover_table_structure");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  if (num_fields() != 7)
  {
    DBUG_PRINT("info",("spider num_fields != 7"));
    my_printf_error(ER_SPIDER_UNKNOWN_NUM, ER_SPIDER_UNKNOWN_STR, MYF(0));
    DBUG_RETURN(ER_SPIDER_UNKNOWN_NUM);
  }
  do {
    if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    if (str->append(mysql_row[0], strlen(mysql_row[0]), access_charset))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN + SPIDER_SQL_SPACE_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
    if (str->append(mysql_row[5], strlen(mysql_row[5]), access_charset))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    if (mysql_row[3])
    {
      length = strlen(mysql_row[3]);
      if (str->reserve(SPIDER_SQL_CHARACTER_SET_LEN + length))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_CHARACTER_SET_STR, SPIDER_SQL_CHARACTER_SET_LEN);
      str->q_append(mysql_row[3], length);
    }
    if (mysql_row[4])
    {
      length = strlen(mysql_row[4]);
      if (str->reserve(SPIDER_SQL_COLLATE_LEN + length))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_COLLATE_STR, SPIDER_SQL_COLLATE_LEN);
      str->q_append(mysql_row[4], length);
    }
    if (!strcmp(mysql_row[2], "NO"))
    {
      if (str->reserve(SPIDER_SQL_NOT_NULL_LEN))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_NOT_NULL_STR, SPIDER_SQL_NOT_NULL_LEN);
      if (mysql_row[1])
      {
        if (str->reserve(SPIDER_SQL_DEFAULT_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_DEFAULT_STR, SPIDER_SQL_DEFAULT_LEN);
        if (str->append(mysql_row[1], strlen(mysql_row[1]), access_charset))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
      }
    } else {
      if (str->reserve(SPIDER_SQL_DEFAULT_LEN))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_DEFAULT_STR, SPIDER_SQL_DEFAULT_LEN);
      if (mysql_row[1])
      {
        if (str->append(mysql_row[1], strlen(mysql_row[1]), access_charset))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
      } else {
        if (str->reserve(SPIDER_SQL_NULL_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_NULL_STR, SPIDER_SQL_NULL_LEN);
      }
    }
    if (mysql_row[6] && !strcmp(mysql_row[6], "auto_increment"))
    {
      if (str->reserve(SPIDER_SQL_AUTO_INCREMENT_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_AUTO_INCREMENT_STR, SPIDER_SQL_AUTO_INCREMENT_LEN);
    }
    if (str->reserve(SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  } while ((mysql_row = mysql_fetch_row(db_result)));
  if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
  {
    my_message(error_num,
      mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_result::fetch_index_for_discover_table_structure(
  spider_string *str,
  CHARSET_INFO *access_charset
) {
  int error_num;
  MYSQL_ROW mysql_row;
  DBUG_ENTER("spider_db_mbase_result::fetch_index_for_discover_table_structure");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    DBUG_RETURN(0);
  }
  if (num_fields() < 13)
  {
    DBUG_PRINT("info",("spider num_fields < 13"));
    my_printf_error(ER_SPIDER_CANT_NUM, ER_SPIDER_CANT_STR1, MYF(0),
                    "fetch index for table structure discovery because of "
                    "wrong number of columns in SHOW INDEX FROM output: ",
                    num_fields());
    DBUG_RETURN(ER_SPIDER_UNKNOWN_NUM);
  }
  bool first = TRUE;
  bool without_size = FALSE;
  bool using_hash = FALSE;
  do {
    if (!strcmp(mysql_row[3], "1"))
    {
      without_size = FALSE;
      if (first)
      {
        first = FALSE;
      } else {
        if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN +
          (using_hash ? SPIDER_SQL_USING_HASH_LEN : 0)))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
        if (using_hash)
          str->q_append(SPIDER_SQL_USING_HASH_STR, SPIDER_SQL_USING_HASH_LEN);
        str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      }
      /* new index */
      if (!strcmp(mysql_row[2], SPIDER_DB_PK_NAME_STR))
      {
        /* primary key */
        if (str->reserve(SPIDER_DB_PK_NAME_LEN + SPIDER_SQL_SPACE_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_DB_PK_NAME_STR, SPIDER_DB_PK_NAME_LEN);
        str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
      } else if (!strcmp(mysql_row[1], "0"))
      {
        /* unique key */
        if (str->reserve(SPIDER_DB_UNIQUE_NAME_LEN + SPIDER_SQL_SPACE_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_DB_UNIQUE_NAME_STR, SPIDER_DB_UNIQUE_NAME_LEN);
        str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
      } else if (mysql_row[10] && !strcmp(mysql_row[10], "FULLTEXT"))
      {
        /* fulltext key */
        if (str->reserve(SPIDER_SQL_FULLTEXT_LEN + SPIDER_SQL_SPACE_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_FULLTEXT_STR, SPIDER_SQL_FULLTEXT_LEN);
        str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
      } else if (mysql_row[10] && !strcmp(mysql_row[10], "SPATIAL"))
      {
        /* spatial key */
        without_size = TRUE;
        if (str->reserve(SPIDER_SQL_SPATIAL_LEN + SPIDER_SQL_SPACE_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_SPATIAL_STR, SPIDER_SQL_SPATIAL_LEN);
        str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
      }
      if (str->reserve(SPIDER_DB_KEY_NAME_LEN + SPIDER_SQL_SPACE_LEN))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_DB_KEY_NAME_STR, SPIDER_DB_KEY_NAME_LEN);
      str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
      if (strcmp(mysql_row[2], SPIDER_DB_PK_NAME_STR))
      {
        if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
        if (str->append(mysql_row[2], strlen(mysql_row[2]), access_charset))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
      }
      if (str->reserve(SPIDER_SQL_OPEN_PAREN_LEN))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
      if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
      if (str->append(mysql_row[4], strlen(mysql_row[4]), access_charset))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
      if (mysql_row[7] && !without_size)
      {
        if (str->reserve(SPIDER_SQL_OPEN_PAREN_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
        if (str->append(mysql_row[7], strlen(mysql_row[7]), access_charset))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
      }
    } else {
      if (str->reserve(SPIDER_SQL_COMMA_LEN + SPIDER_SQL_NAME_QUOTE_LEN))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
      if (str->append(mysql_row[4], strlen(mysql_row[4]), access_charset))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
      if (mysql_row[7] && !without_size)
      {
        if (str->reserve(SPIDER_SQL_OPEN_PAREN_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
        if (str->append(mysql_row[7], strlen(mysql_row[7]), access_charset))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN))
        {
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
      }
    }
    if (mysql_row[10] && !strcmp(mysql_row[10], "HASH"))
      using_hash = TRUE;
    else
      using_hash = FALSE;
  } while ((mysql_row = mysql_fetch_row(db_result)));
  if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
  {
    my_message(error_num,
      mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
    DBUG_RETURN(error_num);
  }
  if (!first)
  {
    if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN +
      (using_hash ? SPIDER_SQL_USING_HASH_LEN : 0)))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
    if (using_hash)
      str->q_append(SPIDER_SQL_USING_HASH_STR, SPIDER_SQL_USING_HASH_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_result::fetch_table_for_discover_table_structure(
  spider_string *str,
  SPIDER_SHARE *spider_share,
  CHARSET_INFO *access_charset
) {
  int error_num;
  MYSQL_ROW mysql_row;
  myf utf8_flag= global_system_variables.old_behavior &
                 OLD_MODE_UTF8_IS_UTF8MB3 ? MY_UTF8_IS_UTF8MB3 : 0;
  DBUG_ENTER("spider_db_mbase_result::fetch_table_for_discover_table_structure");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(mysql_row = mysql_fetch_row(db_result)))
  {
    DBUG_PRINT("info",("spider fetch row is null"));
    if ((error_num = mysql_errno(((spider_db_mbase *) db_conn)->db_conn)))
    {
      my_message(error_num,
        mysql_error(((spider_db_mbase *) db_conn)->db_conn), MYF(0));
      DBUG_RETURN(error_num);
    }
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  if (num_fields() < 18)
  {
    DBUG_PRINT("info",("spider num_fields != 18"));
    my_printf_error(ER_SPIDER_UNKNOWN_NUM, ER_SPIDER_UNKNOWN_STR, MYF(0));
    DBUG_RETURN(ER_SPIDER_UNKNOWN_NUM);
  }
  if (!mysql_row[14])
  {
    DBUG_PRINT("info",("spider mysql_row[14] is null"));
    my_printf_error(ER_SPIDER_UNKNOWN_NUM, ER_SPIDER_UNKNOWN_STR, MYF(0));
    DBUG_RETURN(ER_SPIDER_UNKNOWN_NUM);
  }
  DBUG_PRINT("info",("spider mysql_row[14]=%s", mysql_row[14]));
  if (!spider_share->table_share->table_charset)
  {
    spider_share->table_share->table_charset = get_charset_by_name(mysql_row[14],
                                                                   MYF(utf8_flag | MY_WME));
  }
  DBUG_RETURN(0);
}

spider_db_mbase::spider_db_mbase(
  SPIDER_CONN *conn,
  spider_db_mbase_util *spider_db_mbase_utility
) : spider_db_conn(conn), spider_db_mbase_utility(spider_db_mbase_utility),
  lock_table_hash_inited(FALSE)
{
  DBUG_ENTER("spider_db_mbase::spider_db_mbase");
  DBUG_PRINT("info",("spider this=%p", this));
  db_conn = NULL;
  DBUG_VOID_RETURN;
}

spider_db_mysql::spider_db_mysql(
  SPIDER_CONN *conn
) : spider_db_mbase(conn, &spider_db_mysql_utility)
{
  DBUG_ENTER("spider_db_mysql::spider_db_mysql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mariadb::spider_db_mariadb(
  SPIDER_CONN *conn
) : spider_db_mbase(conn, &spider_db_mariadb_utility)
{
  DBUG_ENTER("spider_db_mariadb::spider_db_mariadb");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mbase::~spider_db_mbase()
{
  DBUG_ENTER("spider_db_mbase::~spider_db_mbase");
  DBUG_PRINT("info",("spider this=%p", this));
  if (lock_table_hash_inited)
  {
    spider_free_mem_calc(spider_current_trx,
      lock_table_hash_id,
      lock_table_hash.array.max_element *
      lock_table_hash.array.size_of_element);
    my_hash_free(&lock_table_hash);
  }
  DBUG_VOID_RETURN;
}

spider_db_mysql::~spider_db_mysql()
{
  DBUG_ENTER("spider_db_mysql::~spider_db_mysql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mariadb::~spider_db_mariadb()
{
  DBUG_ENTER("spider_db_mariadb::~spider_db_mariadb");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

int spider_db_mbase::init()
{
  DBUG_ENTER("spider_db_mbase::init");
  DBUG_PRINT("info",("spider this=%p", this));
  if (my_hash_init(PSI_INSTRUMENT_ME, &lock_table_hash,
                   spd_charset_utf8mb3_bin, 32, 0, 0, spider_link_get_key, 0,
                   0))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  spider_alloc_calc_mem_init(lock_table_hash, SPD_MID_DB_MBASE_INIT_1);
  spider_alloc_calc_mem(spider_current_trx,
    lock_table_hash,
    lock_table_hash.array.max_element *
    lock_table_hash.array.size_of_element);
  lock_table_hash_inited = TRUE;

  DBUG_RETURN(0);
}

bool spider_db_mbase::is_connected()
{
  DBUG_ENTER("spider_db_mbase::is_connected");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(db_conn);
}

void spider_db_mbase::bg_connect()
{
  DBUG_ENTER("spider_db_mbase::bg_connect");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

int spider_db_mbase::connect(
  char *tgt_host,
  char *tgt_username,
  char *tgt_password,
  long tgt_port,
  char *tgt_socket,
  char *server_name,
  int connect_retry_count,
  longlong connect_retry_interval
) {
  int error_num;
  my_bool connect_mutex = spider_param_connect_mutex();
  DBUG_ENTER("spider_db_mbase::connect");
  DBUG_PRINT("info",("spider this=%p", this));
  while (TRUE)
  {
    THD *thd = current_thd;
    DBUG_PRINT("info",("spider thd->killed=%s",
      thd ? (thd->killed ? "TRUE" : "FALSE") : "NULL"));
    DBUG_PRINT("info",("spider abort_loop=%s",
      *spd_abort_loop ? "TRUE" : "FALSE"));
    if (
      (thd && thd->killed) ||
      *spd_abort_loop
    ) {
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    }

    if (!db_conn)
    {
      if (!(db_conn = mysql_init(NULL)))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }

    mysql_options(db_conn, MYSQL_OPT_READ_TIMEOUT,
      &conn->net_read_timeout);
    mysql_options(db_conn, MYSQL_OPT_WRITE_TIMEOUT,
      &conn->net_write_timeout);
    mysql_options(db_conn, MYSQL_OPT_CONNECT_TIMEOUT,
      &conn->connect_timeout);
    mysql_options(db_conn, MYSQL_OPT_USE_REMOTE_CONNECTION,
      NULL);

    if (
      conn->tgt_ssl_ca_length |
      conn->tgt_ssl_capath_length |
      conn->tgt_ssl_cert_length |
      conn->tgt_ssl_key_length
    ) {
      mysql_options(db_conn, MYSQL_OPT_SSL_KEY, conn->tgt_ssl_key);
      mysql_options(db_conn, MYSQL_OPT_SSL_CERT, conn->tgt_ssl_cert);
      mysql_options(db_conn, MYSQL_OPT_SSL_CA, conn->tgt_ssl_ca);
      mysql_options(db_conn, MYSQL_OPT_SSL_CAPATH, conn->tgt_ssl_capath);
      mysql_options(db_conn, MYSQL_OPT_SSL_CIPHER, conn->tgt_ssl_cipher);
    }
    {
      my_bool verify_flg = conn->tgt_ssl_vsc != 0;
      mysql_options(db_conn, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify_flg);
    }

    if (conn->tgt_default_file)
    {
      DBUG_PRINT("info",("spider tgt_default_file=%s",
        conn->tgt_default_file));
      mysql_options(db_conn, MYSQL_READ_DEFAULT_FILE,
        conn->tgt_default_file);
    }
    if (conn->tgt_default_group)
    {
      DBUG_PRINT("info",("spider tgt_default_group=%s",
        conn->tgt_default_group));
      mysql_options(db_conn, MYSQL_READ_DEFAULT_GROUP,
        conn->tgt_default_group);
    }

    if (!spider_param_same_server_link(thd))
    {
      if (!strcmp(tgt_host, my_localhost) || !tgt_host || !tgt_host[0])
      {
        if (!strcmp(tgt_socket, *spd_mysqld_unix_port))
        {
          my_printf_error(ER_SPIDER_SAME_SERVER_LINK_NUM,
            ER_SPIDER_SAME_SERVER_LINK_STR1, MYF(0),
            tgt_host, tgt_socket);
          DBUG_RETURN(ER_SPIDER_SAME_SERVER_LINK_NUM);
        }
      } else if (!strcmp(tgt_host, "127.0.0.1") ||
        !strcmp(tgt_host, glob_hostname) || !tgt_host || !tgt_host[0])
      {
        if (tgt_port == (long) *spd_mysqld_port)
        {
          my_printf_error(ER_SPIDER_SAME_SERVER_LINK_NUM,
            ER_SPIDER_SAME_SERVER_LINK_STR2, MYF(0),
            tgt_host, tgt_port);
          DBUG_RETURN(ER_SPIDER_SAME_SERVER_LINK_NUM);
        }
      }
    }

    if (connect_mutex)
      pthread_mutex_lock(&spider_open_conn_mutex);
    /* tgt_db not use */
    if (
      !spider_param_dry_access() &&
      !mysql_real_connect(
        db_conn,
        tgt_host,
        tgt_username,
        tgt_password,
        NULL,
        tgt_port,
        tgt_socket,
        CLIENT_MULTI_STATEMENTS
      )
    ) {
      if (connect_mutex)
        pthread_mutex_unlock(&spider_open_conn_mutex);
      error_num = mysql_errno(db_conn);
      disconnect();
      DBUG_PRINT("info",("spider thd->killed=%s",
        thd ? (thd->killed ? "TRUE" : "FALSE") : "NULL"));
      DBUG_PRINT("info",("spider abort_loop=%s",
        *spd_abort_loop ? "TRUE" : "FALSE"));
      if (
        (thd && thd->killed) ||
        *spd_abort_loop
      ) {
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      }
      if (
        (
          error_num != CR_CONN_HOST_ERROR &&
          error_num != CR_CONNECTION_ERROR
        ) ||
        !connect_retry_count
      ) {
        if (error_num == ER_CON_COUNT_ERROR)
        {
          *conn->need_mon = 0;
          my_error(ER_CON_COUNT_ERROR, MYF(0));
          DBUG_RETURN(ER_CON_COUNT_ERROR);
        }
        *conn->need_mon = ER_CONNECT_TO_FOREIGN_DATA_SOURCE;
        my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0),
          server_name ? server_name : tgt_host);
        DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE);
      }
      connect_retry_count--;
      my_sleep((ulong) connect_retry_interval * 1000);
    } else {
      db_conn->net.thd = NULL;
      if (connect_mutex)
        pthread_mutex_unlock(&spider_open_conn_mutex);
      break;
    }
  }
  DBUG_RETURN(0);
}

int spider_db_mbase::ping(
) {
  DBUG_ENTER("spider_db_mbase::ping");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider_param_dry_access())
    DBUG_RETURN(0);
  DBUG_RETURN(simple_command(db_conn, COM_PING, 0, 0, 0));
}

void spider_db_mbase::bg_disconnect()
{
  DBUG_ENTER("spider_db_mbase::bg_disconnect");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

void spider_db_mbase::disconnect()
{
  DBUG_ENTER("spider_db_mbase::disconnect");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider db_conn=%p", db_conn));
  if (db_conn)
  {
    mysql_close(db_conn);
    db_conn = NULL;
  }
  DBUG_VOID_RETURN;
}

int spider_db_mbase::set_net_timeout()
{
  DBUG_ENTER("spider_db_mbase::set_net_timeout");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider conn=%p", conn));
  my_net_set_read_timeout(&db_conn->net, conn->net_read_timeout);
  my_net_set_write_timeout(&db_conn->net, conn->net_write_timeout);
  DBUG_RETURN(0);
}

int spider_db_mbase::exec_query(
  const char *query,
  uint length,
  int quick_mode
) {
  int error_num = 0;
  uint log_result_errors = spider_param_log_result_errors();
  DBUG_ENTER("spider_db_mbase::exec_query");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider_param_general_log())
  {
    const char *tgt_str = conn->tgt_host;
    uint32 tgt_len = conn->tgt_host_length;
    spider_string tmp_query_str;
    tmp_query_str.init_calc_mem(SPD_MID_DB_MBASE_EXEC_QUERY_1);
    if (tmp_query_str.reserve(
      length + conn->tgt_wrapper_length +
      tgt_len + (SPIDER_SQL_SPACE_LEN * 2)))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    tmp_query_str.q_append(conn->tgt_wrapper, conn->tgt_wrapper_length);
    tmp_query_str.q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
    tmp_query_str.q_append(tgt_str, tgt_len);
    tmp_query_str.q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
    tmp_query_str.q_append(query, length);
    general_log_write(current_thd, COM_QUERY, tmp_query_str.ptr(),
      tmp_query_str.length());
  }
  /* There should be a live connection to the data node */
  DBUG_ASSERT(db_conn);
  if (!db_conn)
    DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
  if (!spider_param_dry_access())
  {
    error_num = mysql_real_query(db_conn, query, length);
  }
  if (
    (error_num && log_result_errors >= 1) ||
    (log_result_errors >= 2 && db_conn->warning_count > 0) ||
    (log_result_errors >= 4)
  ) {
    THD *thd = current_thd;
    uint log_result_error_with_sql = spider_param_log_result_error_with_sql();
    if (log_result_error_with_sql)
    {
      time_t cur_time = (time_t) time((time_t*) 0);
      struct tm lt;
      struct tm *l_time = localtime_r(&cur_time, &lt);
      spider_string tmp_query_str;
      tmp_query_str.init_calc_mem(SPD_MID_DB_MBASE_EXEC_QUERY_2);
      uint query_length = thd->query_length();
      if ((log_result_error_with_sql & 2) && query_length)
      {
        Security_context *security_ctx = thd->security_ctx;
        tmp_query_str.length(0);
        if (tmp_query_str.reserve(query_length + 1))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        tmp_query_str.q_append(thd->query(), query_length);
        fprintf(stderr, "%04d%02d%02d %02d:%02d:%02d [RECV SPIDER SQL] "
          "from [%s][%s] to %ld:  "
          "sql: %s\n",
          l_time->tm_year + 1900, l_time->tm_mon + 1, l_time->tm_mday,
          l_time->tm_hour, l_time->tm_min, l_time->tm_sec,
          security_ctx->user ? security_ctx->user : "system user",
          security_ctx->host_or_ip,
          (ulong) thd->thread_id,
          tmp_query_str.c_ptr_safe());
      }
      if (log_result_error_with_sql & 1)
      {
        tmp_query_str.length(0);
        if (tmp_query_str.reserve(length + 1))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        tmp_query_str.q_append(query, length);
        fprintf(stderr, "%04d%02d%02d %02d:%02d:%02d [SEND SPIDER SQL] "
          "from %ld to [%s] %ld:  "
          "sql: %s\n",
          l_time->tm_year + 1900, l_time->tm_mon + 1, l_time->tm_mday,
          l_time->tm_hour, l_time->tm_min, l_time->tm_sec,
          (ulong) thd->thread_id, conn->tgt_host, (ulong) db_conn->thread_id,
          tmp_query_str.c_ptr_safe());
      }
    }
    if (log_result_errors >= 2 && db_conn->warning_count > 0)
    {
      time_t cur_time = (time_t) time((time_t*) 0);
      struct tm lt;
      struct tm *l_time = localtime_r(&cur_time, &lt);
      fprintf(stderr, "%04d%02d%02d %02d:%02d:%02d [WARN SPIDER RESULT] "
        "from [%s] %ld to %ld:  "
        "affected_rows: %llu  id: %llu  status: %u  warning_count: %u\n",
        l_time->tm_year + 1900, l_time->tm_mon + 1, l_time->tm_mday,
        l_time->tm_hour, l_time->tm_min, l_time->tm_sec,
        conn->tgt_host, (ulong) db_conn->thread_id, (ulong) thd->thread_id,
        db_conn->affected_rows, db_conn->insert_id,
        db_conn->server_status, db_conn->warning_count);
      if (spider_param_log_result_errors() >= 3)
        fetch_and_print_warnings(l_time);
    } else if (log_result_errors >= 4)
    {
      time_t cur_time = (time_t) time((time_t*) 0);
      struct tm lt;
      struct tm *l_time = localtime_r(&cur_time, &lt);
      fprintf(stderr, "%04d%02d%02d %02d:%02d:%02d [INFO SPIDER RESULT] "
        "from [%s] %ld to %ld:  "
        "affected_rows: %llu  id: %llu  status: %u  warning_count: %u\n",
        l_time->tm_year + 1900, l_time->tm_mon + 1, l_time->tm_mday,
        l_time->tm_hour, l_time->tm_min, l_time->tm_sec,
        conn->tgt_host, (ulong) db_conn->thread_id, (ulong) thd->thread_id,
        db_conn->affected_rows, db_conn->insert_id,
        db_conn->server_status, db_conn->warning_count);
    }
  }
  DBUG_RETURN(error_num);
}

int spider_db_mbase::get_errno()
{
  DBUG_ENTER("spider_db_mbase::get_errno");
  DBUG_PRINT("info",("spider this=%p", this));
  stored_error = mysql_errno(db_conn);
  DBUG_PRINT("info",("spider stored_error=%d", stored_error));
  DBUG_RETURN(stored_error);
}

const char *spider_db_mbase::get_error()
{
  const char *error_ptr;
  DBUG_ENTER("spider_db_mbase::get_error");
  DBUG_PRINT("info",("spider this=%p", this));
  error_ptr = mysql_error(db_conn);
  DBUG_PRINT("info",("spider error=%s", error_ptr));
  DBUG_RETURN(error_ptr);
}

bool spider_db_mbase::is_server_gone_error(
  int error_num
) {
  bool server_gone;
  DBUG_ENTER("spider_db_mbase::is_server_gone_error");
  DBUG_PRINT("info",("spider this=%p", this));
  server_gone =
    (error_num == CR_SERVER_GONE_ERROR || error_num == CR_SERVER_LOST);
  DBUG_PRINT("info",("spider server_gone=%s", server_gone ? "TRUE" : "FALSE"));
  DBUG_RETURN(server_gone);
}

bool spider_db_mbase::is_dup_entry_error(
  int error_num
) {
  bool dup_entry;
  DBUG_ENTER("spider_db_mbase::is_dup_entry_error");
  DBUG_PRINT("info",("spider this=%p", this));
  dup_entry =
    (
      error_num == ER_DUP_ENTRY ||
      error_num == ER_DUP_KEY ||
      error_num == HA_ERR_FOUND_DUPP_KEY
    );
  DBUG_PRINT("info",("spider dup_entry=%s", dup_entry ? "TRUE" : "FALSE"));
  DBUG_RETURN(dup_entry);
}

bool spider_db_mbase::is_xa_nota_error(
  int error_num
) {
  bool xa_nota;
  DBUG_ENTER("spider_db_mbase::is_xa_nota_error");
  DBUG_PRINT("info",("spider this=%p", this));
  xa_nota =
    (
      error_num == ER_XAER_NOTA ||
      error_num == ER_XA_RBTIMEOUT ||
      error_num == ER_XA_RBDEADLOCK
    );
  DBUG_PRINT("info",("spider xa_nota=%s", xa_nota ? "TRUE" : "FALSE"));
  DBUG_RETURN(xa_nota);
}

int spider_db_mbase::fetch_and_print_warnings(struct tm *l_time)
{
  int error_num = 0;
  DBUG_ENTER("spider_db_mbase::fetch_and_print_warnings");
  DBUG_PRINT("info",("spider this=%p", this));

  if (spider_param_dry_access() || db_conn->status != MYSQL_STATUS_READY ||
      db_conn->server_status & SERVER_MORE_RESULTS_EXISTS ||
      !db_conn->warning_count)
    DBUG_RETURN(0);

  if (mysql_real_query(db_conn, SPIDER_SQL_SHOW_WARNINGS_STR,
                       SPIDER_SQL_SHOW_WARNINGS_LEN))
    DBUG_RETURN(0);

  MYSQL_RES *res= mysql_store_result(db_conn);
  if (!res)
    DBUG_RETURN(0);

  uint num_fields= mysql_num_fields(res);
  if (num_fields != 3)
  {
    mysql_free_result(res);
    DBUG_RETURN(0);
  }

  MYSQL_ROW row= mysql_fetch_row(res);
  if (l_time)
  {
    while (row)
    {
      fprintf(stderr,
              "%04d%02d%02d %02d:%02d:%02d [WARN SPIDER RESULT] from [%s] %ld "
              "to %ld: %s %s %s\n",
              l_time->tm_year + 1900, l_time->tm_mon + 1, l_time->tm_mday,
              l_time->tm_hour, l_time->tm_min, l_time->tm_sec, conn->tgt_host,
              (ulong) db_conn->thread_id, (ulong) current_thd->thread_id, row[0],
              row[1], row[2]);
      row= mysql_fetch_row(res);
    }
  } else {
    while (row)
    {
      DBUG_PRINT("info",("spider row[0]=%s", row[0]));
      DBUG_PRINT("info",("spider row[1]=%s", row[1]));
      DBUG_PRINT("info",("spider row[2]=%s", row[2]));
      longlong res_num =
        (longlong) my_strtoll10(row[1], (char**) NULL, &error_num);
      DBUG_PRINT("info",("spider res_num=%lld", res_num));
      my_printf_error((int) res_num, "%s", MYF(0), row[2]);
      error_num = (int) res_num;
      row = mysql_fetch_row(res);
    }
  }

  mysql_free_result(res);

  DBUG_RETURN(error_num);
}

spider_db_result *spider_db_mbase::store_result(
  spider_db_result_buffer **spider_res_buf,
  st_spider_db_request_key *request_key,
  int *error_num
) {
  spider_db_mbase_result *result;
  DBUG_ENTER("spider_db_mbase::store_result");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_ASSERT(!spider_res_buf);
  if ((result = new spider_db_mbase_result(this)))
  {
    *error_num = 0;
    if (
      spider_param_dry_access() ||
      !(result->db_result = mysql_store_result(db_conn))
    ) {
      delete result;
      result = NULL;
    } else {
      result->first_row = result->db_result->data_cursor;
      DBUG_PRINT("info",("spider result->first_row=%p", result->first_row));
    }
  } else {
    *error_num = HA_ERR_OUT_OF_MEM;
  }
  DBUG_RETURN(result);
}

spider_db_result *spider_db_mbase::use_result(
  ha_spider *spider,
  st_spider_db_request_key *request_key,
  int *error_num
) {
  spider_db_mbase_result *result;
  DBUG_ENTER("spider_db_mbase::use_result");
  DBUG_PRINT("info",("spider this=%p", this));
  if ((result = new spider_db_mbase_result(this)))
  {
    *error_num = 0;
    if (
      spider_param_dry_access() ||
      !(result->db_result = db_conn->methods->use_result(db_conn))
    ) {
      delete result;
      result = NULL;
    } else {
      result->first_row = NULL;
    }
  } else {
    *error_num = HA_ERR_OUT_OF_MEM;
  }
  DBUG_RETURN(result);
}

int spider_db_mbase::next_result()
{
  int status;
  DBUG_ENTER("spider_db_mbase::next_result");
  DBUG_PRINT("info",("spider this=%p", this));
  if (db_conn->status != MYSQL_STATUS_READY)
  {
    my_message(ER_SPIDER_UNKNOWN_NUM, ER_SPIDER_UNKNOWN_STR, MYF(0));
    DBUG_RETURN(ER_SPIDER_UNKNOWN_NUM);
  }

  db_conn->net.last_errno = 0;
  db_conn->net.last_error[0] = '\0';
  strmov(db_conn->net.sqlstate, "00000");
  db_conn->affected_rows = ~(my_ulonglong) 0;

  if (db_conn->server_status & SERVER_MORE_RESULTS_EXISTS)
  {
    if ((status = db_conn->methods->read_query_result(db_conn)) > 0)
      DBUG_RETURN(spider_db_errorno(conn));
    DBUG_RETURN(status);
  }
  DBUG_RETURN(-1);
}

uint spider_db_mbase::affected_rows()
{
  MYSQL *last_used_con;
  DBUG_ENTER("spider_db_mbase::affected_rows");
  DBUG_PRINT("info",("spider this=%p", this));
  last_used_con = db_conn;
  DBUG_RETURN((uint) last_used_con->affected_rows);
}

uint spider_db_mbase::matched_rows()
{
  MYSQL *last_used_con;
  DBUG_ENTER("spider_db_mysql::matched_rows");
  DBUG_PRINT("info", ("spider this=%p", this));
  last_used_con = db_conn;
  /* Rows matched: 65 Changed: 65 Warnings: 0 */
  const char *info = last_used_con->info;
  if (!info)
    DBUG_RETURN(0);
  DBUG_PRINT("info", ("spider info=%s", info));
  const char *begin = strstr(info, "Rows matched: ");
  if (!begin)
    DBUG_RETURN(0);
  DBUG_RETURN(atoi(begin + strlen("Rows matched: ")));
}

bool spider_db_mbase::inserted_info(
  spider_db_handler *handler,
  ha_copy_info *copy_info
) {
  MYSQL *last_used_con;
  uchar direct_insert_kind =
    ((spider_mbase_handler *) handler)->direct_insert_kind;
  DBUG_ENTER("spider_db_mysql::inserted_info");
  DBUG_PRINT("info", ("spider this=%p", this));
  if (direct_insert_kind == SPIDER_SQL_DIRECT_INSERT_KIND_INSERT)
  {
    DBUG_RETURN(TRUE);
  }
  last_used_con = db_conn;
  /* Records: 10  Duplicates: 4  Warnings: 0 */
  const char *info = last_used_con->info;
  if (!info)
    DBUG_RETURN(FALSE);
  DBUG_PRINT("info", ("spider info=%s", info));
  const char *begin = strstr(info, "Records: ");
  if (!begin)
    DBUG_RETURN(FALSE);
  begin += strlen("Records: ");
  uint records = atoi(begin);
  begin = strstr(begin, "Duplicates: ");
  if (!begin)
    DBUG_RETURN(FALSE);
  uint duplicates = atoi(begin + strlen("Duplicates: "));
  copy_info->records+= records;
  switch (direct_insert_kind)
  {
    case SPIDER_SQL_DIRECT_INSERT_KIND_IGNORE:
      copy_info->copied+= duplicates;
      break;
    case SPIDER_SQL_DIRECT_INSERT_KIND_REPLACE:
      copy_info->copied+= records;
      copy_info->deleted+= duplicates;
      break;
    case SPIDER_SQL_DIRECT_INSERT_KIND_DUP_UPDATE:
      copy_info->touched+= (last_used_con->affected_rows - (duplicates * 2));
      copy_info->copied+= (last_used_con->affected_rows - duplicates);
      copy_info->updated+= duplicates;
      break;
    default:
      DBUG_ASSERT(0);
      DBUG_RETURN(FALSE);
  }
  DBUG_RETURN(TRUE);
}

ulonglong spider_db_mbase::last_insert_id()
{
  MYSQL *last_used_con;
  DBUG_ENTER("spider_db_mbase::last_insert_id");
  DBUG_PRINT("info",("spider this=%p", this));
  last_used_con = db_conn;
  DBUG_RETURN((uint) last_used_con->insert_id);
}

int spider_db_mbase::set_character_set(
  const char *csname
) {
  DBUG_ENTER("spider_db_mbase::set_character_set");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider_param_dry_access())
    DBUG_RETURN(0);
  DBUG_RETURN(mysql_set_character_set(db_conn, csname));
}

int spider_db_mbase::select_db(
  const char *dbname
) {
  DBUG_ENTER("spider_db_mbase::select_db");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider_param_dry_access())
    DBUG_RETURN(0);
  DBUG_RETURN(mysql_select_db(db_conn, dbname));
}

static int spider_db_query_with_lock(SPIDER_CONN *conn, const char *query,
                                     uint len, int *need_mon)
{
  int error_num= 0;
  spider_lock_before_query(conn, need_mon);
  if (spider_db_query(conn, query, len, -1, need_mon))
    error_num= spider_db_errorno(conn);
  return spider_unlock_after_query(conn, error_num);
}

int spider_db_mbase::consistent_snapshot(
  int *need_mon
) {
  DBUG_ENTER("spider_db_mbase::consistent_snapshot");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(spider_db_query_with_lock(
                conn, SPIDER_SQL_START_CONSISTENT_SNAPSHOT_STR,
                SPIDER_SQL_START_CONSISTENT_SNAPSHOT_LEN, need_mon));
}

bool spider_db_mbase::trx_start_in_bulk_sql()
{
  DBUG_ENTER("spider_db_mbase::trx_start_in_bulk_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_db_mbase::start_transaction(
  int *need_mon
) {
  DBUG_ENTER("spider_db_mbase::start_transaction");
  DBUG_PRINT("info",("spider this=%p", this));
  pthread_mutex_assert_owner(&conn->mta_conn_mutex);
  DBUG_ASSERT(conn->mta_conn_mutex_lock_already);
  DBUG_ASSERT(conn->mta_conn_mutex_unlock_later);
  if (spider_db_query(
    conn,
    SPIDER_SQL_START_TRANSACTION_STR,
    SPIDER_SQL_START_TRANSACTION_LEN,
    -1,
    need_mon)
  ) {
    DBUG_RETURN(spider_db_errorno(conn));
  }
  DBUG_RETURN(0);
}

int spider_db_mbase::commit(
  int *need_mon
) {
  DBUG_ENTER("spider_db_mbase::commit");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(spider_db_query_with_lock(conn, SPIDER_SQL_COMMIT_STR,
                                        SPIDER_SQL_COMMIT_LEN, need_mon));
}

int spider_db_mbase::rollback(
  int *need_mon
) {
  bool is_error, save_in_before_query;
  int error_num= 0;
  DBUG_ENTER("spider_db_mbase::rollback");
  DBUG_PRINT("info",("spider this=%p", this));
  spider_lock_before_query(conn, need_mon);
  save_in_before_query= conn->in_before_query;
  /*
    We do not execute the before queries to avoid unnecessary
    failures in rollback
  */
  conn->in_before_query= TRUE;
  error_num= spider_db_query(conn, SPIDER_SQL_ROLLBACK_STR,
                             SPIDER_SQL_ROLLBACK_LEN, -1, need_mon);
  conn->in_before_query= save_in_before_query;
  if (error_num)
  {
    is_error= conn->thd->is_error();
    error_num= spider_db_errorno(conn);
    if (error_num == ER_SPIDER_REMOTE_SERVER_GONE_AWAY_NUM && !is_error)
    {
      conn->thd->clear_error();
      error_num= 0;
    }
  }
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_db_mbase::xa_start(
  XID *xid,
  int *need_mon
) {
  DBUG_ENTER("spider_db_mbase::xa_start");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_ASSERT(0);
  DBUG_RETURN(0);
}

bool spider_db_mbase::xa_start_in_bulk_sql()
{
  DBUG_ENTER("spider_db_mbase::xa_start_in_bulk_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_db_mbase::xa_end(
  XID *xid,
  int *need_mon
) {
  char sql_buf[SPIDER_SQL_XA_END_LEN + XIDDATASIZE + sizeof(long) + 9];
  spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin);
  DBUG_ENTER("spider_db_mbase::xa_end");
  DBUG_PRINT("info",("spider this=%p", this));
  sql_str.init_calc_mem(SPD_MID_DB_MBASE_XA_END_1);

  sql_str.length(0);
  sql_str.q_append(SPIDER_SQL_XA_END_STR, SPIDER_SQL_XA_END_LEN);
  spider_db_append_xid_str(&sql_str, xid);
  DBUG_RETURN(spider_db_query_with_lock(conn, sql_str.ptr(),
                                        sql_str.length(), need_mon));
}

int spider_db_mbase::xa_prepare(
  XID *xid,
  int *need_mon
) {
  char sql_buf[SPIDER_SQL_XA_PREPARE_LEN + XIDDATASIZE + sizeof(long) + 9];
  spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin);
  DBUG_ENTER("spider_db_mbase::xa_prepare");
  DBUG_PRINT("info",("spider this=%p", this));
  sql_str.init_calc_mem(SPD_MID_DB_MBASE_XA_PREPARE_1);

  sql_str.length(0);
  sql_str.q_append(SPIDER_SQL_XA_PREPARE_STR, SPIDER_SQL_XA_PREPARE_LEN);
  spider_db_append_xid_str(&sql_str, xid);
  DBUG_RETURN(spider_db_query_with_lock(conn, sql_str.ptr(),
                                        sql_str.length(), need_mon));
}

int spider_db_mbase::xa_commit(
  XID *xid,
  int *need_mon
) {
  char sql_buf[SPIDER_SQL_XA_COMMIT_LEN + XIDDATASIZE + sizeof(long) + 9];
  spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin);
  DBUG_ENTER("spider_db_mbase::xa_commit");
  DBUG_PRINT("info",("spider this=%p", this));
  sql_str.init_calc_mem(SPD_MID_DB_MBASE_XA_COMMIT_1);

  sql_str.length(0);
  sql_str.q_append(SPIDER_SQL_XA_COMMIT_STR, SPIDER_SQL_XA_COMMIT_LEN);
  spider_db_append_xid_str(&sql_str, xid);
  DBUG_RETURN(spider_db_query_with_lock(conn, sql_str.ptr(),
                                        sql_str.length(), need_mon));
}

int spider_db_mbase::xa_rollback(
  XID *xid,
  int *need_mon
) {
  char sql_buf[SPIDER_SQL_XA_ROLLBACK_LEN + XIDDATASIZE + sizeof(long) + 9];
  spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin);
  DBUG_ENTER("spider_db_mbase::xa_rollback");
  DBUG_PRINT("info",("spider this=%p", this));
  sql_str.init_calc_mem(SPD_MID_DB_MBASE_XA_ROLLBACK_1);

  sql_str.length(0);
  sql_str.q_append(SPIDER_SQL_XA_ROLLBACK_STR, SPIDER_SQL_XA_ROLLBACK_LEN);
  spider_db_append_xid_str(&sql_str, xid);
  DBUG_RETURN(spider_db_query_with_lock(conn, sql_str.ptr(),
                                        sql_str.length(), need_mon));
}

bool spider_db_mbase::set_trx_isolation_in_bulk_sql()
{
  DBUG_ENTER("spider_db_mbase::set_trx_isolation_in_bulk_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_db_mbase::set_trx_isolation(
  int trx_isolation,
  int *need_mon
) {
  DBUG_ENTER("spider_db_mbase::set_trx_isolation");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (trx_isolation)
  {
    case ISO_READ_UNCOMMITTED:
      DBUG_RETURN(spider_db_query_with_lock(
                    conn, SPIDER_SQL_ISO_READ_UNCOMMITTED_STR,
                    SPIDER_SQL_ISO_READ_UNCOMMITTED_LEN, need_mon));
    case ISO_READ_COMMITTED:
      DBUG_RETURN(spider_db_query_with_lock(
                    conn, SPIDER_SQL_ISO_READ_COMMITTED_STR,
                    SPIDER_SQL_ISO_READ_COMMITTED_LEN, need_mon));
    case ISO_REPEATABLE_READ:
      DBUG_RETURN(spider_db_query_with_lock(
                    conn, SPIDER_SQL_ISO_REPEATABLE_READ_STR,
                    SPIDER_SQL_ISO_REPEATABLE_READ_LEN, need_mon));
    case ISO_SERIALIZABLE:
      DBUG_RETURN(spider_db_query_with_lock(
                    conn, SPIDER_SQL_ISO_SERIALIZABLE_STR,
                    SPIDER_SQL_ISO_SERIALIZABLE_LEN, need_mon));
    default:
      DBUG_RETURN(HA_ERR_UNSUPPORTED);
  }
  DBUG_RETURN(0);
}

bool spider_db_mbase::set_autocommit_in_bulk_sql()
{
  DBUG_ENTER("spider_db_mbase::set_autocommit_in_bulk_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_db_mbase::set_autocommit(
  bool autocommit,
  int *need_mon
) {
  DBUG_ENTER("spider_db_mbase::set_autocommit");
  DBUG_PRINT("info",("spider this=%p", this));
  if (autocommit)
    DBUG_RETURN(spider_db_query_with_lock(
                  conn, SPIDER_SQL_AUTOCOMMIT_ON_STR,
                  SPIDER_SQL_AUTOCOMMIT_ON_LEN, need_mon));
  DBUG_RETURN(spider_db_query_with_lock(
                conn, SPIDER_SQL_AUTOCOMMIT_OFF_STR,
                SPIDER_SQL_AUTOCOMMIT_OFF_LEN, need_mon));
}

bool spider_db_mbase::set_sql_log_off_in_bulk_sql()
{
  DBUG_ENTER("spider_db_mbase::set_sql_log_off_in_bulk_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_db_mbase::set_sql_log_off(
  bool sql_log_off,
  int *need_mon
) {
  DBUG_ENTER("spider_db_mbase::set_sql_log_off");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql_log_off)
    DBUG_RETURN(spider_db_query_with_lock(
                  conn, SPIDER_SQL_SQL_LOG_ON_STR,
                  SPIDER_SQL_SQL_LOG_ON_LEN, need_mon));
  DBUG_RETURN(spider_db_query_with_lock(
                conn, SPIDER_SQL_SQL_LOG_OFF_STR,
                SPIDER_SQL_SQL_LOG_OFF_LEN, need_mon));
}

bool spider_db_mbase::set_wait_timeout_in_bulk_sql()
{
  DBUG_ENTER("spider_db_mbase::set_wait_timeout_in_bulk_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_db_mbase::set_wait_timeout(
  int wait_timeout,
  int *need_mon
) {
  char sql_buf[MAX_FIELD_WIDTH];
  char timeout_str[SPIDER_SQL_INT_LEN];
  int timeout_str_length;
  spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin);
  DBUG_ENTER("spider_db_mbase::set_wait_timeout");
  DBUG_PRINT("info",("spider this=%p", this));
  sql_str.init_calc_mem(SPD_MID_DB_MBASE_SET_WAIT_TIMEOUT_1);
  sql_str.length(0);
  timeout_str_length =
    my_sprintf(timeout_str, (timeout_str, "%d", wait_timeout));
  if (sql_str.reserve(SPIDER_SQL_WAIT_TIMEOUT_LEN + timeout_str_length))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql_str.q_append(SPIDER_SQL_WAIT_TIMEOUT_STR, SPIDER_SQL_WAIT_TIMEOUT_LEN);
  sql_str.q_append(timeout_str, timeout_str_length);
  DBUG_RETURN(spider_db_query_with_lock(
                conn, sql_str.ptr(), sql_str.length(), need_mon));
}

bool spider_db_mbase::set_sql_mode_in_bulk_sql()
{
  DBUG_ENTER("spider_db_mbase::set_sql_mode_in_bulk_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_db_mbase::set_sql_mode(
  sql_mode_t sql_mode,
  int *need_mon
) {
  int error_num;
  char sql_buf[MAX_FIELD_WIDTH];
  spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin);
  DBUG_ENTER("spider_db_mbase::set_sql_mode");
  DBUG_PRINT("info",("spider this=%p", this));
  sql_str.init_calc_mem(SPD_MID_DB_MBASE_SET_SQL_MODE_1);
  sql_str.length(0);
  if (sql_str.reserve(SPIDER_SQL_SQL_MODE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql_str.q_append(SPIDER_SQL_SQL_MODE_STR, SPIDER_SQL_SQL_MODE_LEN);
  if ((error_num = spider_db_mbase_utility->append_sql_mode_internal(&sql_str, sql_mode)))
  {
    DBUG_RETURN(error_num);
  }
  if (sql_str.length() > SPIDER_SQL_SQL_MODE_LEN)
  {
    sql_str.length(sql_str.length() - SPIDER_SQL_COMMA_LEN);
  } else {
    if (sql_str.reserve(SPIDER_SQL_VALUE_QUOTE_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
  }
  sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  DBUG_RETURN(spider_db_query_with_lock(
                conn, sql_str.ptr(), sql_str.length(), need_mon));
}

bool spider_db_mbase::set_time_zone_in_bulk_sql()
{
  DBUG_ENTER("spider_db_mbase::set_time_zone_in_bulk_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_db_mbase::set_time_zone(
  Time_zone *time_zone,
  int *need_mon
) {
  const String *tz_str = time_zone->get_name();
  char sql_buf[MAX_FIELD_WIDTH];
  spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin);
  DBUG_ENTER("spider_db_mbase::set_time_zone");
  DBUG_PRINT("info",("spider this=%p", this));
  sql_str.init_calc_mem(SPD_MID_DB_MBASE_SET_TIME_ZONE_1);
  sql_str.length(0);
  if (sql_str.reserve(SPIDER_SQL_TIME_ZONE_LEN +
    tz_str->length() + SPIDER_SQL_VALUE_QUOTE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql_str.q_append(SPIDER_SQL_TIME_ZONE_STR, SPIDER_SQL_TIME_ZONE_LEN);
  sql_str.q_append(tz_str->ptr(), tz_str->length());
  sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  DBUG_RETURN(spider_db_query_with_lock(
                conn, sql_str.ptr(), sql_str.length(), need_mon));
}

int spider_db_mbase::exec_simple_sql_with_result(
  SPIDER_TRX *trx,
  SPIDER_SHARE *share,
  const char *sql,
  uint sql_length,
  int all_link_idx,
  int *need_mon,
  SPIDER_DB_RESULT **res
) {
  int error_num= 0;
  DBUG_ENTER("spider_db_mbase::exec_simple_sql_with_result");
  spider_lock_before_query(conn, need_mon);
  spider_conn_set_timeout_from_share(conn, all_link_idx, trx->thd, share);
  if (
    (error_num = spider_db_set_names_internal(trx, share, conn,
      all_link_idx, need_mon)) ||
    (
      spider_db_query(
        conn,
        sql,
        sql_length,
        -1,
        need_mon) &&
      (error_num = spider_db_errorno(conn))
    )
  ) {
      if (
        error_num == ER_SPIDER_REMOTE_SERVER_GONE_AWAY_NUM &&
        !conn->disable_reconnect
      ) {
        if ((error_num = spider_db_ping_internal(share, conn,
          all_link_idx, need_mon)))
          goto unlock;
        if ((error_num= spider_db_set_names_internal(trx, share, conn,
          all_link_idx, need_mon)))
          goto unlock;
        spider_conn_set_timeout_from_share(conn, all_link_idx, trx->thd,
          share);
        if (spider_db_query(
              conn,
              sql,
              sql_length,
              -1,
              need_mon)
        ) {
          error_num= spider_db_errorno(conn);
          goto unlock;
        }
      } else
        goto unlock;
    }
    if (!(*res = store_result(NULL, NULL, &error_num)))
    {
      if (error_num || (error_num= spider_db_errorno(conn)) ||
          (error_num= ER_QUERY_ON_FOREIGN_DATA_SOURCE))
        goto unlock;
    }
unlock:
    DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_db_mbase::show_master_status(
  SPIDER_TRX *trx,
  SPIDER_SHARE *share,
  int all_link_idx,
  int *need_mon,
  TABLE *table,
  spider_string *str,
  int mode,
  SPIDER_DB_RESULT **res1,
  SPIDER_DB_RESULT **res2
) {
  int error_num;
  const char *binlog_file_name, *binlog_pos;
  uint binlog_file_name_length, binlog_pos_length;
  DBUG_ENTER("spider_db_mbase::show_master_status");
  if ((error_num = exec_simple_sql_with_result(trx, share,
    SPIDER_SQL_SHOW_MASTER_STATUS_STR, SPIDER_SQL_SHOW_MASTER_STATUS_LEN,
    all_link_idx, need_mon, res1))
  ) {
    DBUG_PRINT("info", ("spider error_num=%d 1", error_num));
    DBUG_RETURN(error_num);
  }

  if (!(error_num = ((spider_db_mbase_result *)*res1)->fetch_show_master_status(
    &binlog_file_name, &binlog_pos))
  ) {
    binlog_file_name_length = strlen(binlog_file_name);
    binlog_pos_length = strlen(binlog_pos);
    spider_store_binlog_pos_binlog_file(table,
      binlog_file_name, binlog_file_name_length,
      binlog_pos, binlog_pos_length, conn->access_charset);
    if (mode > 0)
    {
      error_num = select_binlog_gtid_pos(
        trx,
        share,
        all_link_idx,
        need_mon,
        table,
        str,
        binlog_file_name,
        binlog_file_name_length,
        binlog_pos,
        binlog_pos_length,
        res2
      );
    } else {
      spider_store_binlog_pos_gtid(table, NULL, 0, conn->access_charset);
    }
  }
  if (error_num)
  {
    DBUG_PRINT("info", ("spider error_num=%d 2", error_num));
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase::select_binlog_gtid_pos(
  SPIDER_TRX *trx,
  SPIDER_SHARE *share,
  int all_link_idx,
  int *need_mon,
  TABLE *table,
  spider_string *str,
  const char *binlog_file_name,
  uint binlog_file_name_length,
  const char *binlog_pos,
  uint binlog_pos_length,
  SPIDER_DB_RESULT **res
) {
  int error_num;
  size_t length;
  const char *gtid_pos;
  DBUG_ENTER("spider_db_mbase::select_binlog_gtid_pos");
  str->length(0);
  if (str->reserve(
    SPIDER_SQL_BINLOG_GTID_POS_LEN +
    SPIDER_SQL_OPEN_PAREN_LEN +
    SPIDER_SQL_VALUE_QUOTE_LEN +
    binlog_file_name_length * 2 +
    SPIDER_SQL_VALUE_QUOTE_LEN +
    SPIDER_SQL_COMMA_LEN +
    SPIDER_SQL_VALUE_QUOTE_LEN +
    binlog_pos_length * 2 +
    SPIDER_SQL_VALUE_QUOTE_LEN +
    SPIDER_SQL_CLOSE_PAREN_LEN
  ))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_BINLOG_GTID_POS_STR,
    SPIDER_SQL_BINLOG_GTID_POS_LEN);
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  length = conn->db_conn->escape_string((char *)str->ptr() + str->length(),
     binlog_file_name, binlog_file_name_length);
  str->length(str->length() + length);
  str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  length = conn->db_conn->escape_string((char *)str->ptr() + str->length(),
     binlog_pos, binlog_pos_length);
  str->length(str->length() + length);
  str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);

  if ((error_num = exec_simple_sql_with_result(trx, share,
    str->ptr(), str->length(), all_link_idx, need_mon, res)))
  {
    DBUG_PRINT("info", ("spider error_num=%d 1", error_num));
    DBUG_RETURN(error_num);
  }
  if (!(error_num = ((spider_db_mbase_result *)*res)->fetch_select_binlog_gtid_pos(&gtid_pos)))
  {
    spider_store_binlog_pos_gtid(table, gtid_pos, strlen(gtid_pos), conn->access_charset);
  }
  if (error_num)
  {
    DBUG_PRINT("info", ("spider error_num=%d 2", error_num));
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

size_t spider_db_mbase::escape_string(
  char *to,
  const char *from,
  size_t from_length
) {
  my_bool overflow;
  DBUG_ENTER("spider_db_mbase::escape_string");
  DBUG_PRINT("info",("spider this=%p", this));
  if (db_conn->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
    DBUG_RETURN(escape_quotes_for_mysql(db_conn->charset, to, 0,
      from, from_length, &overflow));
  DBUG_RETURN(escape_string_for_mysql(db_conn->charset, to, 0,
    from, from_length, &overflow));
}

bool spider_db_mbase::have_lock_table_list()
{
  DBUG_ENTER("spider_db_mbase::have_lock_table_list");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(lock_table_hash.records);
}

int spider_db_mbase::append_lock_tables(
  spider_string *str
) {
  int error_num;
  ha_spider *tmp_spider;
  int lock_type;
  uint all_link_idx;
  int tmp_link_idx;
  SPIDER_LINK_FOR_HASH *tmp_link_for_hash;
  const char *db_name;
  uint db_name_length;
  CHARSET_INFO *db_name_charset;
  const char *table_name;
  uint table_name_length;
  CHARSET_INFO *table_name_charset;
  DBUG_ENTER("spider_db_mbase::lock_tables");
  DBUG_PRINT("info",("spider this=%p", this));
  if ((error_num = spider_db_mbase_utility->append_lock_table_head(str)))
  {
    DBUG_RETURN(error_num);
  }
  while ((tmp_link_for_hash =
    (SPIDER_LINK_FOR_HASH *) my_hash_element(&lock_table_hash, 0)))
  {
    tmp_spider = tmp_link_for_hash->spider;
    tmp_link_idx = tmp_link_for_hash->link_idx;
    switch (tmp_spider->wide_handler->lock_type)
    {
      case TL_READ:
        lock_type = SPIDER_DB_TABLE_LOCK_READ_LOCAL;
        break;
      case TL_READ_NO_INSERT:
        lock_type = SPIDER_DB_TABLE_LOCK_READ;
        break;
      case TL_WRITE_LOW_PRIORITY:
        lock_type = SPIDER_DB_TABLE_LOCK_LOW_PRIORITY_WRITE;
        break;
      case TL_WRITE:
        lock_type = SPIDER_DB_TABLE_LOCK_WRITE;
        break;
      default:
        // no lock
        DBUG_PRINT("info",("spider lock_type=%d",
          tmp_spider->wide_handler->lock_type));
        DBUG_RETURN(0);
    }
    all_link_idx = tmp_spider->conn_link_idx[tmp_link_idx];
    spider_mbase_share *db_share = (spider_mbase_share *)
      tmp_spider->share->dbton_share[conn->dbton_id];

    db_name = db_share->db_names_str[all_link_idx].ptr();
    db_name_length = db_share->db_names_str[all_link_idx].length();
    db_name_charset = tmp_spider->share->access_charset;

    table_name = db_share->table_names_str[all_link_idx].ptr();
    table_name_length = db_share->table_names_str[all_link_idx].length();
    table_name_charset = tmp_spider->share->access_charset;

    if ((error_num = spider_db_mbase_utility->
      append_lock_table_body(
        str,
        db_name,
        db_name_length,
        db_name_charset,
        table_name,
        table_name_length,
        table_name_charset,
        lock_type
      )
    )) {
      my_hash_reset(&lock_table_hash);
      DBUG_RETURN(error_num);
    }
    my_hash_delete(&lock_table_hash, (uchar*) tmp_link_for_hash);
  }
  if ((error_num = spider_db_mbase_utility->append_lock_table_tail(str)))
  {
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase::append_unlock_tables(
  spider_string *str
) {
  int error_num;
  DBUG_ENTER("spider_db_mbase::append_unlock_tables");
  DBUG_PRINT("info",("spider this=%p", this));
  if ((error_num = spider_db_mbase_utility->append_unlock_table(str)))
  {
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

uint spider_db_mbase::get_lock_table_hash_count()
{
  DBUG_ENTER("spider_db_mbase::get_lock_table_hash_count");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(lock_table_hash.records);
}

void spider_db_mbase::reset_lock_table_hash()
{
  DBUG_ENTER("spider_db_mbase::reset_lock_table_hash");
  DBUG_PRINT("info",("spider this=%p", this));
  my_hash_reset(&lock_table_hash);
  DBUG_VOID_RETURN;
}

void spider_db_mbase::set_dup_key_idx(
  ha_spider *spider,
  int link_idx
) {
  TABLE *table = spider->get_table();
  uint roop_count, pk_idx = table->s->primary_key;
  int key_name_length;
  int max_length = 0;
  const char *key_name;
  DBUG_ENTER("spider_db_mbase::set_dup_key_idx");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider error_str=%s", conn->error_str));
  for (roop_count = 0; roop_count < table->s->keys; roop_count++)
  {
    if (roop_count == pk_idx)
    {
      DBUG_PRINT("info",("spider pk_idx=%u", roop_count));
      int all_link_idx = spider->conn_link_idx[link_idx];
      key_name = spider->share->tgt_pk_names[all_link_idx];
      key_name_length = spider->share->tgt_pk_names_lengths[all_link_idx];
    } else {
      key_name = table->key_info[roop_count].name.str;
      key_name_length = table->key_info[roop_count].name.length;
    }
    DBUG_PRINT("info",("spider key_name=%s", key_name));
    if (
      max_length < key_name_length &&
      conn->error_length - 1 >= key_name_length &&
      *(conn->error_str + conn->error_length - 2 -
        key_name_length) == '\'' &&
      !strncasecmp(conn->error_str +
        conn->error_length - 1 - key_name_length,
        key_name, key_name_length)
    ) {
      max_length = key_name_length;
      spider->dup_key_idx = roop_count;
    }
  }
  if (max_length == 0)
    spider->dup_key_idx = (uint) -1;
  DBUG_PRINT("info",("spider dup_key_idx=%d", spider->dup_key_idx));
  DBUG_VOID_RETURN;
}

bool spider_db_mbase::cmp_request_key_to_snd(
  st_spider_db_request_key *request_key
) {
  DBUG_ENTER("spider_db_mbase::cmp_request_key_to_snd");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

spider_db_mbase_util::spider_db_mbase_util() : spider_db_util()
{
  DBUG_ENTER("spider_db_mbase_util::spider_db_mbase_util");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mysql_util::spider_db_mysql_util() : spider_db_mbase_util()
{
  DBUG_ENTER("spider_db_mysql_util::spider_db_mysql_util");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mariadb_util::spider_db_mariadb_util() : spider_db_mbase_util()
{
  DBUG_ENTER("spider_db_mariadb_util::spider_db_mariadb_util");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mbase_util::~spider_db_mbase_util()
{
  DBUG_ENTER("spider_db_mbase_util::~spider_db_mbase_util");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mysql_util::~spider_db_mysql_util()
{
  DBUG_ENTER("spider_db_mysql_util::~spider_db_mysql_util");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_db_mariadb_util::~spider_db_mariadb_util()
{
  DBUG_ENTER("spider_db_mariadb_util::~spider_db_mariadb_util");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

int spider_db_mbase_util::append_name(
  spider_string *str,
  const char *name,
  uint name_length
) {
  DBUG_ENTER("spider_db_mbase_util::append_name");
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  str->q_append(name, name_length);
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_name_with_charset(
  spider_string *str,
  const char *name,
  uint name_length,
  CHARSET_INFO *name_charset
) {
  DBUG_ENTER("spider_db_mbase_util::append_name_with_charset");
  if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN * 2 + name_length * 2))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  str->append(name, name_length, name_charset);
  if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_escaped_name(
  spider_string *str,
  const char *name,
  uint name_length
) {
  int error_num;
  DBUG_ENTER("spider_db_mbase_util::append_name");
  if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN * 2 + name_length * 2))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  if ((error_num = spider_db_append_name_with_quote_str_internal(
    str, name, name_length, dbton_id)))
  {
    DBUG_RETURN(error_num);
  }
  if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_escaped_name_with_charset(
  spider_string *str,
  const char *name,
  uint name_length,
  CHARSET_INFO *name_charset
) {
  int error_num;
  DBUG_ENTER("spider_db_mbase_util::append_name_with_charset");
  if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN * 2 + name_length * 2))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  if ((error_num = spider_db_append_name_with_quote_str_internal(
    str, name, name_length, name_charset, dbton_id)))
  {
    DBUG_RETURN(error_num);
  }
  if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  DBUG_RETURN(0);
}

bool spider_db_mbase_util::is_name_quote(
  const char head_code
) {
  DBUG_ENTER("spider_db_mbase_util::is_name_quote");
  DBUG_RETURN(head_code == *name_quote_str);
}

int spider_db_mbase_util::append_escaped_name_quote(
  spider_string *str
) {
  DBUG_ENTER("spider_db_mbase_util::append_escaped_name_quote");
  if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN * 2))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  DBUG_RETURN(0);
}

int spider_db_mariadb_util::append_column_value(ha_spider *spider,
                                                spider_string *str,
                                                Field *field,
                                                const uchar *new_ptr,
                                                bool is_like,
                                                CHARSET_INFO *access_charset)
{
  bool float_value = FALSE;
  int error_num;
  char buf[MAX_FIELD_WIDTH];
  spider_string tmp_str(buf, MAX_FIELD_WIDTH, field->charset());
  String *ptr;
  uint length;
  THD *thd = field->table->in_use;
  Time_zone *saved_time_zone = thd->variables.time_zone;
  DBUG_ENTER("spider_db_mariadb_util::append_column_value");
  tmp_str.init_calc_mem(SPD_MID_DB_MARIADB_UTIL_APPEND_COLUMN_VALUE_1);

  thd->variables.time_zone = UTC;

  if (new_ptr)
  {
    if (
      field->type() == MYSQL_TYPE_BLOB ||
      field->real_type() == MYSQL_TYPE_VARCHAR
    ) {
      length = uint2korr(new_ptr);
      tmp_str.set((char *) new_ptr + HA_KEY_BLOB_LENGTH, length,
        field->charset());
      ptr = tmp_str.get_str();
    } else if (field->type() == MYSQL_TYPE_GEOMETRY)
    {
#ifdef DBUG_TRACE
      double xmin, xmax, ymin, ymax;
      float8get(xmin, new_ptr);
      float8get(xmax, new_ptr + 8);
      float8get(ymin, new_ptr + 16);
      float8get(ymax, new_ptr + 24);
      DBUG_PRINT("info", ("spider geo is %f %f %f %f",
        xmin, xmax, ymin, ymax));
#endif
      tmp_str.length(0);
      tmp_str.q_append((char *) SPIDER_SQL_LINESTRING_HEAD_STR,
        SPIDER_SQL_LINESTRING_HEAD_LEN);
      tmp_str.q_append((char *) new_ptr, SIZEOF_STORED_DOUBLE);
      tmp_str.q_append((char *) new_ptr + SIZEOF_STORED_DOUBLE * 2,
        SIZEOF_STORED_DOUBLE);
      tmp_str.q_append((char *) new_ptr + SIZEOF_STORED_DOUBLE,
        SIZEOF_STORED_DOUBLE);
      tmp_str.q_append((char *) new_ptr + SIZEOF_STORED_DOUBLE * 3,
        SIZEOF_STORED_DOUBLE);
      ptr = tmp_str.get_str();
    } else {
      ptr = field->val_str(tmp_str.get_str(), new_ptr);
      tmp_str.mem_calc();
    }
  } else {
    ptr = field->val_str(tmp_str.get_str());
    tmp_str.mem_calc();
    if (field->type() == MYSQL_TYPE_FLOAT)
    {
      float_value = TRUE;
    }
  }

  thd->variables.time_zone = saved_time_zone;

  DBUG_PRINT("info", ("spider field->type() is %d", field->type()));
  DBUG_PRINT("info", ("spider ptr->length() is %d", ptr->length()));

  if (field->result_type() == STRING_RESULT)
  {
    DBUG_PRINT("info", ("spider STRING_RESULT"));
    if (str->charset() != field->charset())
    {
      if ((error_num = spider_db_append_charset_name_before_string(str,
        field->charset())))
      {
        DBUG_RETURN(error_num);
      }
    }
    if (str->reserve(SPIDER_SQL_VALUE_QUOTE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    if (
      field->type() == MYSQL_TYPE_VARCHAR ||
      (field->type() >= MYSQL_TYPE_ENUM &&
        field->type() <= MYSQL_TYPE_GEOMETRY)
    ) {
      DBUG_PRINT("info", ("spider append_escaped"));
      char buf2[MAX_FIELD_WIDTH];
      spider_string tmp_str2(buf2, MAX_FIELD_WIDTH, field->charset());
      tmp_str2.init_calc_mem(SPD_MID_DB_MARIADB_UTIL_APPEND_COLUMN_VALUE_2);
      tmp_str2.length(0);
      if (
        tmp_str2.append(ptr->ptr(), ptr->length(), field->charset()) ||
        str->reserve(tmp_str2.length() * 2) ||
        append_escaped_util(str, tmp_str2.get_str())
      )
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);

      if (is_like &&
          str->append(SPIDER_SQL_PERCENT_STR, SPIDER_SQL_PERCENT_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    } else if (str->append(*ptr))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    if (str->reserve(SPIDER_SQL_VALUE_QUOTE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  } else if (field->str_needs_quotes())
  {
    if (str->charset() != field->charset())
    {
      if ((error_num = spider_db_append_charset_name_before_string(str,
        field->charset())))
      {
        DBUG_RETURN(error_num);
      }
    }
    if (str->reserve(SPIDER_SQL_VALUE_QUOTE_LEN * 2 + ptr->length() * 2 + 2))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    append_escaped_util(str, ptr);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  } else if (float_value)
  {
    if (str->reserve(SPIDER_SQL_CAST_LEN + ptr->length() +
                     SPIDER_SQL_AS_FLOAT_LEN + SPIDER_SQL_CLOSE_PAREN_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
    str->q_append(ptr->ptr(), ptr->length());
    str->q_append(SPIDER_SQL_AS_FLOAT_STR, SPIDER_SQL_AS_FLOAT_LEN);
    str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  } else if (str->append(*ptr))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }

  DBUG_RETURN(0);
}

int spider_db_mysql_util::append_column_value(
  ha_spider *spider,
  spider_string *str,
  Field *field,
  const uchar *new_ptr,
  bool is_like,
  CHARSET_INFO *access_charset
) {
  bool float_value = FALSE;
  int error_num;
  char buf[MAX_FIELD_WIDTH];
  spider_string tmp_str(buf, MAX_FIELD_WIDTH, field->charset());
  String *ptr;
  uint length;
  THD *thd = field->table->in_use;
  Time_zone *saved_time_zone = thd->variables.time_zone;
  DBUG_ENTER("spider_db_mysql_util::append_column_value");
  tmp_str.init_calc_mem(SPD_MID_DB_MYSQL_UTIL_APPEND_COLUMN_VALUE_1);

  thd->variables.time_zone = UTC;

  if (new_ptr)
  {
    if (
      field->type() == MYSQL_TYPE_BLOB ||
      field->real_type() == MYSQL_TYPE_VARCHAR
    ) {
      length = uint2korr(new_ptr);
      tmp_str.set((char *) new_ptr + HA_KEY_BLOB_LENGTH, length,
        field->charset());
      ptr = tmp_str.get_str();
    } else if (field->type() == MYSQL_TYPE_GEOMETRY)
    {
#ifdef DBUG_TRACE
      double xmin, xmax, ymin, ymax;
      float8get(xmin, new_ptr);
      float8get(xmax, new_ptr + 8);
      float8get(ymin, new_ptr + 16);
      float8get(ymax, new_ptr + 24);
      DBUG_PRINT("info", ("spider geo is %f %f %f %f",
        xmin, xmax, ymin, ymax));
#endif
      tmp_str.length(0);
      tmp_str.q_append((char *) SPIDER_SQL_LINESTRING_HEAD_STR,
        SPIDER_SQL_LINESTRING_HEAD_LEN);
      tmp_str.q_append((char *) new_ptr, SIZEOF_STORED_DOUBLE);
      tmp_str.q_append((char *) new_ptr + SIZEOF_STORED_DOUBLE * 2,
        SIZEOF_STORED_DOUBLE);
      tmp_str.q_append((char *) new_ptr + SIZEOF_STORED_DOUBLE,
        SIZEOF_STORED_DOUBLE);
      tmp_str.q_append((char *) new_ptr + SIZEOF_STORED_DOUBLE * 3,
        SIZEOF_STORED_DOUBLE);
      ptr = tmp_str.get_str();
    } else {
      ptr = field->val_str(tmp_str.get_str(), new_ptr);
      tmp_str.mem_calc();
    }
  } else {
    ptr = field->val_str(tmp_str.get_str());
    tmp_str.mem_calc();
    if (field->type() == MYSQL_TYPE_FLOAT)
    {
      float_value = TRUE;
    }
  }

  thd->variables.time_zone = saved_time_zone;

  DBUG_PRINT("info", ("spider field->type() is %d", field->type()));
  DBUG_PRINT("info", ("spider ptr->length() is %d", ptr->length()));
  if (field->result_type() == STRING_RESULT)
  {
    DBUG_PRINT("info", ("spider STRING_RESULT"));
    if (str->charset() != field->charset())
    {
      if ((error_num = spider_db_append_charset_name_before_string(str,
        field->charset())))
      {
        DBUG_RETURN(error_num);
      }
    }
    if (str->reserve(SPIDER_SQL_VALUE_QUOTE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    if (
      field->type() == MYSQL_TYPE_VARCHAR ||
      (field->type() >= MYSQL_TYPE_ENUM &&
        field->type() <= MYSQL_TYPE_GEOMETRY)
    ) {
      DBUG_PRINT("info", ("spider append_escaped"));
      char buf2[MAX_FIELD_WIDTH];
      spider_string tmp_str2(buf2, MAX_FIELD_WIDTH, field->charset());
      tmp_str2.init_calc_mem(SPD_MID_DB_MYSQL_UTIL_APPEND_COLUMN_VALUE_2);
      tmp_str2.length(0);
      if (
        tmp_str2.append(ptr->ptr(), ptr->length(), field->charset()) ||
        str->reserve(tmp_str2.length() * 2) ||
        append_escaped_util(str, tmp_str2.get_str())
      )
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      if (is_like &&
          str->append(SPIDER_SQL_PERCENT_STR, SPIDER_SQL_PERCENT_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    } else if (str->append(*ptr))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    if (str->reserve(SPIDER_SQL_VALUE_QUOTE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  } else if (field->str_needs_quotes())
  {
    if (str->charset() != field->charset())
    {
      if ((error_num = spider_db_append_charset_name_before_string(str,
        field->charset())))
      {
        DBUG_RETURN(error_num);
      }
    }
    if (str->reserve(SPIDER_SQL_VALUE_QUOTE_LEN * 2 + ptr->length() * 2 + 2))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    append_escaped_util(str, ptr);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  } else if (float_value)
  {
    if (str->reserve(SPIDER_SQL_TO_FLOAT_LEN + ptr->length() +
      SPIDER_SQL_CLOSE_PAREN_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SQL_TO_FLOAT_STR, SPIDER_SQL_TO_FLOAT_LEN);
    str->q_append(ptr->ptr(), ptr->length());
    str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  } else if (str->append(*ptr))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_column_value(ha_spider *, spider_string *,
                                              Field *, const uchar *, bool,
                                              CHARSET_INFO *)
{
  MY_ASSERT_UNREACHABLE();
  return 0;
}

int spider_db_mbase_util::append_from_with_alias(
  spider_string *str,
  const char **table_names,
  uint *table_name_lengths,
  const char **table_aliases,
  uint *table_alias_lengths,
  uint table_count,
  int *table_name_pos,
  bool over_write
) {
  uint roop_count, length = 0;
  DBUG_ENTER("spider_db_mbase_util::append_from_with_alias");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!over_write)
  {
    for (roop_count = 0; roop_count < table_count; roop_count++)
      length += table_name_lengths[roop_count] + SPIDER_SQL_SPACE_LEN +
        table_alias_lengths[roop_count] + SPIDER_SQL_COMMA_LEN;
    if (str->reserve(SPIDER_SQL_FROM_LEN + length))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_FROM_STR, SPIDER_SQL_FROM_LEN);
    *table_name_pos = str->length();
  }
  for (roop_count = 0; roop_count < table_count; roop_count++)
  {
    str->q_append(table_names[roop_count], table_name_lengths[roop_count]);
    str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
    str->q_append(table_aliases[roop_count], table_alias_lengths[roop_count]);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_trx_isolation(
  spider_string *str,
  int trx_isolation
) {
  DBUG_ENTER("spider_db_mbase_util::append_trx_isolation");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SEMICOLON_LEN +
    SPIDER_SQL_ISO_READ_UNCOMMITTED_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  if (str->length())
  {
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }
  switch (trx_isolation)
  {
    case ISO_READ_UNCOMMITTED:
      str->q_append(SPIDER_SQL_ISO_READ_UNCOMMITTED_STR,
        SPIDER_SQL_ISO_READ_UNCOMMITTED_LEN);
      break;
    case ISO_READ_COMMITTED:
      str->q_append(SPIDER_SQL_ISO_READ_COMMITTED_STR,
        SPIDER_SQL_ISO_READ_COMMITTED_LEN);
      break;
    case ISO_REPEATABLE_READ:
      str->q_append(SPIDER_SQL_ISO_REPEATABLE_READ_STR,
        SPIDER_SQL_ISO_REPEATABLE_READ_LEN);
      break;
    case ISO_SERIALIZABLE:
      str->q_append(SPIDER_SQL_ISO_SERIALIZABLE_STR,
        SPIDER_SQL_ISO_SERIALIZABLE_LEN);
      break;
    default:
      DBUG_RETURN(HA_ERR_UNSUPPORTED);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_autocommit(
  spider_string *str,
  bool autocommit
) {
  DBUG_ENTER("spider_db_mbase_util::append_autocommit");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SEMICOLON_LEN + SPIDER_SQL_AUTOCOMMIT_OFF_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  if (str->length())
  {
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }
  if (autocommit)
  {
    str->q_append(SPIDER_SQL_AUTOCOMMIT_ON_STR,
      SPIDER_SQL_AUTOCOMMIT_ON_LEN);
  } else {
    str->q_append(SPIDER_SQL_AUTOCOMMIT_OFF_STR,
      SPIDER_SQL_AUTOCOMMIT_OFF_LEN);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_sql_log_off(
  spider_string *str,
  bool sql_log_off
) {
  DBUG_ENTER("spider_db_mbase_util::append_sql_log_off");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SEMICOLON_LEN + SPIDER_SQL_SQL_LOG_OFF_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  if (str->length())
  {
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }
  if (sql_log_off)
  {
    str->q_append(SPIDER_SQL_SQL_LOG_ON_STR, SPIDER_SQL_SQL_LOG_ON_LEN);
  } else {
    str->q_append(SPIDER_SQL_SQL_LOG_OFF_STR, SPIDER_SQL_SQL_LOG_OFF_LEN);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_wait_timeout(
  spider_string *str,
  int wait_timeout
) {
  char timeout_str[SPIDER_SQL_INT_LEN];
  int timeout_str_length;
  DBUG_ENTER("spider_db_mbase_util::append_wait_timeout");
  DBUG_PRINT("info",("spider this=%p", this));
  timeout_str_length =
    my_sprintf(timeout_str, (timeout_str, "%d", wait_timeout));
  if (str->reserve(SPIDER_SQL_SEMICOLON_LEN + SPIDER_SQL_WAIT_TIMEOUT_LEN +
    timeout_str_length))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  if (str->length())
  {
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }
  str->q_append(SPIDER_SQL_WAIT_TIMEOUT_STR, SPIDER_SQL_WAIT_TIMEOUT_LEN);
  str->q_append(timeout_str, timeout_str_length);
  DBUG_RETURN(0);
}

#define SPIDER_REAL_AS_FLOAT_STR              "real_as_float"
#define SPIDER_REAL_AS_FLOAT_LEN              (sizeof(SPIDER_REAL_AS_FLOAT_STR) - 1)
#define SPIDER_PIPES_AS_CONCAT_STR            "pipes_as_concat"
#define SPIDER_PIPES_AS_CONCAT_LEN            (sizeof(SPIDER_PIPES_AS_CONCAT_STR) - 1)
#define SPIDER_ANSI_QUOTES_STR                "ansi_quotes"
#define SPIDER_ANSI_QUOTES_LEN                (sizeof(SPIDER_ANSI_QUOTES_STR) - 1)
#define SPIDER_IGNORE_SPACE_STR               "ignore_space"
#define SPIDER_IGNORE_SPACE_LEN               (sizeof(SPIDER_IGNORE_SPACE_STR) - 1)
#define SPIDER_IGNORE_BAD_TABLE_OPTIONS_STR   "ignore_bad_table_options"
#define SPIDER_IGNORE_BAD_TABLE_OPTIONS_LEN   (sizeof(SPIDER_IGNORE_BAD_TABLE_OPTIONS_STR) - 1)
#define SPIDER_ONLY_FULL_GROUP_BY_STR         "only_full_group_by"
#define SPIDER_ONLY_FULL_GROUP_BY_LEN         (sizeof(SPIDER_ONLY_FULL_GROUP_BY_STR) - 1)
#define SPIDER_NO_UNSIGNED_SUBTRACTION_STR    "no_unsigned_subtraction"
#define SPIDER_NO_UNSIGNED_SUBTRACTION_LEN    (sizeof(SPIDER_NO_UNSIGNED_SUBTRACTION_STR) - 1)
#define SPIDER_NO_DIR_IN_CREATE_STR           "no_dir_in_create"
#define SPIDER_NO_DIR_IN_CREATE_LEN           (sizeof(SPIDER_NO_DIR_IN_CREATE_STR) - 1)
#define SPIDER_POSTGRESQL_STR                 "postgresql"
#define SPIDER_POSTGRESQL_LEN                 (sizeof(SPIDER_POSTGRESQL_STR) - 1)
#define SPIDER_ORACLE_STR                     "oracle"
#define SPIDER_ORACLE_LEN                     (sizeof(SPIDER_ORACLE_STR) - 1)
#define SPIDER_MSSQL_STR                      "mssql"
#define SPIDER_MSSQL_LEN                      (sizeof(SPIDER_MSSQL_STR) - 1)
#define SPIDER_DB2_STR                        "db2"
#define SPIDER_DB2_LEN                        (sizeof(SPIDER_DB2_STR) - 1)
#define SPIDER_MAXDB_STR                      "maxdb"
#define SPIDER_MAXDB_LEN                      (sizeof(SPIDER_MAXDB_STR) - 1)
#define SPIDER_NO_KEY_OPTIONS_STR             "no_key_options"
#define SPIDER_NO_KEY_OPTIONS_LEN             (sizeof(SPIDER_NO_KEY_OPTIONS_STR) - 1)
#define SPIDER_NO_TABLE_OPTIONS_STR           "no_table_options"
#define SPIDER_NO_TABLE_OPTIONS_LEN           (sizeof(SPIDER_NO_TABLE_OPTIONS_STR) - 1)
#define SPIDER_NO_FIELD_OPTIONS_STR           "no_field_options"
#define SPIDER_NO_FIELD_OPTIONS_LEN           (sizeof(SPIDER_NO_FIELD_OPTIONS_STR) - 1)
#define SPIDER_MYSQL323_STR                   "mysql323"
#define SPIDER_MYSQL323_LEN                   (sizeof(SPIDER_MYSQL323_STR) - 1)
#define SPIDER_MYSQL40_STR                    "mysql40"
#define SPIDER_MYSQL40_LEN                    (sizeof(SPIDER_MYSQL40_STR) - 1)
#define SPIDER_ANSI_STR                       "ansi"
#define SPIDER_ANSI_LEN                       (sizeof(SPIDER_ANSI_STR) - 1)
#define SPIDER_NO_AUTO_VALUE_ON_ZERO_STR      "no_auto_value_on_zero"
#define SPIDER_NO_AUTO_VALUE_ON_ZERO_LEN      (sizeof(SPIDER_NO_AUTO_VALUE_ON_ZERO_STR) - 1)
#define SPIDER_NO_BACKSLASH_ESCAPES_STR       "no_backslash_escapes"
#define SPIDER_NO_BACKSLASH_ESCAPES_LEN       (sizeof(SPIDER_NO_BACKSLASH_ESCAPES_STR) - 1)
#define SPIDER_STRICT_TRANS_TABLES_STR        "strict_trans_tables"
#define SPIDER_STRICT_TRANS_TABLES_LEN        (sizeof(SPIDER_STRICT_TRANS_TABLES_STR) - 1)
#define SPIDER_STRICT_ALL_TABLES_STR          "strict_all_tables"
#define SPIDER_STRICT_ALL_TABLES_LEN          (sizeof(SPIDER_STRICT_ALL_TABLES_STR) - 1)
#define SPIDER_NO_ZERO_IN_DATE_STR            "no_zero_in_date"
#define SPIDER_NO_ZERO_IN_DATE_LEN            (sizeof(SPIDER_NO_ZERO_IN_DATE_STR) - 1)
#define SPIDER_NO_ZERO_DATE_STR               "no_zero_date"
#define SPIDER_NO_ZERO_DATE_LEN               (sizeof(SPIDER_NO_ZERO_DATE_STR) - 1)
#define SPIDER_INVALID_DATES_STR              "allow_invalid_dates"
#define SPIDER_INVALID_DATES_LEN              (sizeof(SPIDER_INVALID_DATES_STR) - 1)
#define SPIDER_ERROR_FOR_DIVISION_BY_ZERO_STR "error_for_division_by_zero"
#define SPIDER_ERROR_FOR_DIVISION_BY_ZERO_LEN (sizeof(SPIDER_ERROR_FOR_DIVISION_BY_ZERO_STR) - 1)
#define SPIDER_TRADITIONAL_STR                "traditional"
#define SPIDER_TRADITIONAL_LEN                (sizeof(SPIDER_TRADITIONAL_STR) - 1)
#define SPIDER_NO_AUTO_CREATE_USER_STR        "no_auto_create_user"
#define SPIDER_NO_AUTO_CREATE_USER_LEN        (sizeof(SPIDER_NO_AUTO_CREATE_USER_STR) - 1)
#define SPIDER_HIGH_NOT_PRECEDENCE_STR        "high_not_precedence"
#define SPIDER_HIGH_NOT_PRECEDENCE_LEN        (sizeof(SPIDER_HIGH_NOT_PRECEDENCE_STR) - 1)
#define SPIDER_NO_ENGINE_SUBSTITUTION_STR     "no_engine_substitution"
#define SPIDER_NO_ENGINE_SUBSTITUTION_LEN     (sizeof(SPIDER_NO_ENGINE_SUBSTITUTION_STR) - 1)
#define SPIDER_PAD_CHAR_TO_FULL_LENGTH_STR    "pad_char_to_full_length"
#define SPIDER_PAD_CHAR_TO_FULL_LENGTH_LEN    (sizeof(SPIDER_PAD_CHAR_TO_FULL_LENGTH_STR) - 1)
#define SPIDER_EMPTY_STRING_IS_NULL_STR       "empty_string_is_null"
#define SPIDER_EMPTY_STRING_IS_NULL_LEN       (sizeof(SPIDER_EMPTY_STRING_IS_NULL_STR) - 1)
#define SPIDER_SIMULTANEOUS_ASSIGNMENT_STR    "simultaneous_assignment"
#define SPIDER_SIMULTANEOUS_ASSIGNMENT_LEN    (sizeof(SPIDER_SIMULTANEOUS_ASSIGNMENT_STR) - 1)
#define SPIDER_TIME_ROUND_FRACTIONAL_STR      "time_round_fractional"
#define SPIDER_TIME_ROUND_FRACTIONAL_LEN      (sizeof(SPIDER_TIME_ROUND_FRACTIONAL_STR) - 1)

sql_mode_t full_sql_mode =
#ifdef MODE_REAL_AS_FLOAT
  MODE_REAL_AS_FLOAT |
#endif
#ifdef MODE_PIPES_AS_CONCAT
  MODE_PIPES_AS_CONCAT |
#endif
#ifdef MODE_ANSI_QUOTES
  MODE_ANSI_QUOTES |
#endif
#ifdef MODE_IGNORE_SPACE
  MODE_IGNORE_SPACE |
#endif
#ifdef MODE_IGNORE_BAD_TABLE_OPTIONS
  MODE_IGNORE_BAD_TABLE_OPTIONS |
#endif
#ifdef MODE_ONLY_FULL_GROUP_BY
  MODE_ONLY_FULL_GROUP_BY |
#endif
#ifdef MODE_NO_UNSIGNED_SUBTRACTION
  MODE_NO_UNSIGNED_SUBTRACTION |
#endif
#ifdef MODE_NO_DIR_IN_CREATE
  MODE_NO_DIR_IN_CREATE |
#endif
#ifdef MODE_POSTGRESQL
  MODE_POSTGRESQL |
#endif
#ifdef MODE_ORACLE
  MODE_ORACLE |
#endif
#ifdef MODE_MSSQL
  MODE_MSSQL |
#endif
#ifdef MODE_DB2
  MODE_DB2 |
#endif
#ifdef MODE_MAXDB
  MODE_MAXDB |
#endif
#ifdef MODE_NO_KEY_OPTIONS
  MODE_NO_KEY_OPTIONS |
#endif
#ifdef MODE_NO_TABLE_OPTIONS
  MODE_NO_TABLE_OPTIONS |
#endif
#ifdef MODE_NO_FIELD_OPTIONS
  MODE_NO_FIELD_OPTIONS |
#endif
#ifdef MODE_MYSQL323
  MODE_MYSQL323 |
#endif
#ifdef MODE_MYSQL40
  MODE_MYSQL40 |
#endif
#ifdef MODE_ANSI
  MODE_ANSI |
#endif
#ifdef MODE_NO_AUTO_VALUE_ON_ZERO
  MODE_NO_AUTO_VALUE_ON_ZERO |
#endif
#ifdef MODE_NO_BACKSLASH_ESCAPES
  MODE_NO_BACKSLASH_ESCAPES |
#endif
#ifdef MODE_STRICT_TRANS_TABLES
  MODE_STRICT_TRANS_TABLES |
#endif
#ifdef MODE_STRICT_ALL_TABLES
  MODE_STRICT_ALL_TABLES |
#endif
#ifdef MODE_NO_ZERO_IN_DATE
  MODE_NO_ZERO_IN_DATE |
#endif
#ifdef MODE_NO_ZERO_DATE
  MODE_NO_ZERO_DATE |
#endif
#ifdef MODE_INVALID_DATES
  MODE_INVALID_DATES |
#endif
#ifdef MODE_ERROR_FOR_DIVISION_BY_ZERO
  MODE_ERROR_FOR_DIVISION_BY_ZERO |
#endif
#ifdef MODE_TRADITIONAL
  MODE_TRADITIONAL |
#endif
#ifdef MODE_NO_AUTO_CREATE_USER
  MODE_NO_AUTO_CREATE_USER |
#endif
#ifdef MODE_HIGH_NOT_PRECEDENCE
  MODE_HIGH_NOT_PRECEDENCE |
#endif
#ifdef MODE_NO_ENGINE_SUBSTITUTION
  MODE_NO_ENGINE_SUBSTITUTION |
#endif
#ifdef MODE_PAD_CHAR_TO_FULL_LENGTH
  MODE_PAD_CHAR_TO_FULL_LENGTH |
#endif
#ifdef MODE_EMPTY_STRING_IS_NULL
  MODE_EMPTY_STRING_IS_NULL |
#endif
#ifdef MODE_SIMULTANEOUS_ASSIGNMENT
  MODE_SIMULTANEOUS_ASSIGNMENT |
#endif
#ifdef MODE_TIME_ROUND_FRACTIONAL
  MODE_TIME_ROUND_FRACTIONAL |
#endif
  0;

#ifdef MODE_REAL_AS_FLOAT
/* pushdown */
#define SPIDER_SQL_MODE_REAL_AS_FLOAT
#endif
#ifdef MODE_PIPES_AS_CONCAT
/* no pushdown */
#endif
#ifdef MODE_ANSI_QUOTES
/* no pushdown */
#endif
#ifdef MODE_IGNORE_SPACE
/* no pushdown */
#endif
#ifdef MODE_IGNORE_BAD_TABLE_OPTIONS
/* pushdown */
#define SPIDER_SQL_MODE_IGNORE_BAD_TABLE_OPTIONS
#endif
#ifdef MODE_ONLY_FULL_GROUP_BY
/* no pushdown */
#endif
#ifdef MODE_NO_UNSIGNED_SUBTRACTION
/* pushdown */
#define SPIDER_SQL_MODE_NO_UNSIGNED_SUBTRACTION
#endif
#ifdef MODE_NO_DIR_IN_CREATE
/* pushdown */
#define SPIDER_SQL_MODE_NO_DIR_IN_CREATE
#endif
#ifdef MODE_POSTGRESQL
/* no pushdown */
#endif
#ifdef MODE_ORACLE
/* no pushdown */
#endif
#ifdef MODE_MSSQL
/* no pushdown */
#endif
#ifdef MODE_DB2
/* no pushdown */
#endif
#ifdef MODE_MAXDB
/* no pushdown */
#endif
#ifdef MODE_NO_KEY_OPTIONS
/* no pushdown */
#endif
#ifdef MODE_NO_TABLE_OPTIONS
/* no pushdown */
#endif
#ifdef MODE_NO_FIELD_OPTIONS
/* no pushdown */
#endif
#ifdef MODE_MYSQL323
/* no pushdown */
#endif
#ifdef MODE_MYSQL40
/* no pushdown */
#endif
#ifdef MODE_ANSI
/* no pushdown */
#endif
#ifdef MODE_NO_AUTO_VALUE_ON_ZERO
/* pushdown */
#define SPIDER_SQL_MODE_NO_AUTO_VALUE_ON_ZERO
#endif
#ifdef MODE_NO_BACKSLASH_ESCAPES
/* no pushdown */
#endif
#ifdef MODE_STRICT_TRANS_TABLES
/* pushdown */
#define SPIDER_SQL_MODE_STRICT_TRANS_TABLES
#endif
#ifdef MODE_STRICT_ALL_TABLES
/* pushdown */
#define SPIDER_SQL_MODE_STRICT_ALL_TABLES
#endif
#ifdef MODE_NO_ZERO_IN_DATE
/* pushdown */
#define SPIDER_SQL_MODE_NO_ZERO_IN_DATE
#endif
#ifdef MODE_NO_ZERO_DATE
/* pushdown */
#define SPIDER_SQL_MODE_NO_ZERO_DATE
#endif
#ifdef MODE_INVALID_DATES
/* pushdown */
#define SPIDER_SQL_MODE_INVALID_DATES
#endif
#ifdef MODE_ERROR_FOR_DIVISION_BY_ZERO
/* pushdown */
#define SPIDER_SQL_MODE_ERROR_FOR_DIVISION_BY_ZERO
#endif
#ifdef MODE_TRADITIONAL
/* no pushdown */
#endif
#ifdef MODE_NO_AUTO_CREATE_USER
/* pushdown */
#define SPIDER_SQL_MODE_NO_AUTO_CREATE_USER
#endif
#ifdef MODE_HIGH_NOT_PRECEDENCE
/* pushdown */
#define SPIDER_SQL_MODE_HIGH_NOT_PRECEDENCE
#endif
#ifdef MODE_NO_ENGINE_SUBSTITUTION
/* pushdown */
#define SPIDER_SQL_MODE_NO_ENGINE_SUBSTITUTION
#endif
#ifdef MODE_PAD_CHAR_TO_FULL_LENGTH
/* pushdown */
#define SPIDER_SQL_MODE_PAD_CHAR_TO_FULL_LENGTH
#endif
#ifdef MODE_EMPTY_STRING_IS_NULL
/* pushdown */
#define SPIDER_SQL_MODE_EMPTY_STRING_IS_NULL
#endif
#ifdef MODE_SIMULTANEOUS_ASSIGNMENT
/* pushdown */
#define SPIDER_SQL_MODE_SIMULTANEOUS_ASSIGNMENT
#endif
#ifdef MODE_TIME_ROUND_FRACTIONAL
/* pushdown */
#define SPIDER_SQL_MODE_TIME_ROUND_FRACTIONAL
#endif

sql_mode_t pushdown_sql_mode =
#ifdef SPIDER_SQL_MODE_REAL_AS_FLOAT
  MODE_REAL_AS_FLOAT |
#endif
#ifdef SPIDER_SQL_MODE_PIPES_AS_CONCAT
  MODE_PIPES_AS_CONCAT |
#endif
#ifdef SPIDER_SQL_MODE_ANSI_QUOTES
  MODE_ANSI_QUOTES |
#endif
#ifdef SPIDER_SQL_MODE_IGNORE_SPACE
  MODE_IGNORE_SPACE |
#endif
#ifdef SPIDER_SQL_MODE_IGNORE_BAD_TABLE_OPTIONS
  MODE_IGNORE_BAD_TABLE_OPTIONS |
#endif
#ifdef SPIDER_SQL_MODE_ONLY_FULL_GROUP_BY
  MODE_ONLY_FULL_GROUP_BY |
#endif
#ifdef SPIDER_SQL_MODE_NO_UNSIGNED_SUBTRACTION
  MODE_NO_UNSIGNED_SUBTRACTION |
#endif
#ifdef SPIDER_SQL_MODE_NO_DIR_IN_CREATE
  MODE_NO_DIR_IN_CREATE |
#endif
#ifdef SPIDER_SQL_MODE_POSTGRESQL
  MODE_POSTGRESQL |
#endif
#ifdef SPIDER_SQL_MODE_ORACLE
  MODE_ORACLE |
#endif
#ifdef SPIDER_SQL_MODE_MSSQL
  MODE_MSSQL |
#endif
#ifdef SPIDER_SQL_MODE_DB2
  MODE_DB2 |
#endif
#ifdef SPIDER_SQL_MODE_MAXDB
  MODE_MAXDB |
#endif
#ifdef SPIDER_SQL_MODE_NO_KEY_OPTIONS
  MODE_NO_KEY_OPTIONS |
#endif
#ifdef SPIDER_SQL_MODE_NO_TABLE_OPTIONS
  MODE_NO_TABLE_OPTIONS |
#endif
#ifdef SPIDER_SQL_MODE_NO_FIELD_OPTIONS
  MODE_NO_FIELD_OPTIONS |
#endif
#ifdef SPIDER_SQL_MODE_MYSQL323
  MODE_MYSQL323 |
#endif
#ifdef SPIDER_SQL_MODE_MYSQL40
  MODE_MYSQL40 |
#endif
#ifdef SPIDER_SQL_MODE_ANSI
  MODE_ANSI |
#endif
#ifdef SPIDER_SQL_MODE_NO_AUTO_VALUE_ON_ZERO
  MODE_NO_AUTO_VALUE_ON_ZERO |
#endif
#ifdef SPIDER_SQL_MODE_NO_BACKSLASH_ESCAPES
  MODE_NO_BACKSLASH_ESCAPES |
#endif
#ifdef SPIDER_SQL_MODE_STRICT_TRANS_TABLES
  MODE_STRICT_TRANS_TABLES |
#endif
#ifdef SPIDER_SQL_MODE_STRICT_ALL_TABLES
  MODE_STRICT_ALL_TABLES |
#endif
#ifdef SPIDER_SQL_MODE_NO_ZERO_IN_DATE
  MODE_NO_ZERO_IN_DATE |
#endif
#ifdef SPIDER_SQL_MODE_NO_ZERO_DATE
  MODE_NO_ZERO_DATE |
#endif
#ifdef SPIDER_SQL_MODE_INVALID_DATES
  MODE_INVALID_DATES |
#endif
#ifdef SPIDER_SQL_MODE_ERROR_FOR_DIVISION_BY_ZERO
  MODE_ERROR_FOR_DIVISION_BY_ZERO |
#endif
#ifdef SPIDER_SQL_MODE_TRADITIONAL
  MODE_TRADITIONAL |
#endif
#ifdef SPIDER_SQL_MODE_NO_AUTO_CREATE_USER
  MODE_NO_AUTO_CREATE_USER |
#endif
#ifdef SPIDER_SQL_MODE_HIGH_NOT_PRECEDENCE
  MODE_HIGH_NOT_PRECEDENCE |
#endif
#ifdef SPIDER_SQL_MODE_NO_ENGINE_SUBSTITUTION
  MODE_NO_ENGINE_SUBSTITUTION |
#endif
#ifdef SPIDER_SQL_MODE_PAD_CHAR_TO_FULL_LENGTH
  MODE_PAD_CHAR_TO_FULL_LENGTH |
#endif
#ifdef SPIDER_SQL_MODE_EMPTY_STRING_IS_NULL
  MODE_EMPTY_STRING_IS_NULL |
#endif
#ifdef SPIDER_SQL_MODE_SIMULTANEOUS_ASSIGNMENT
  MODE_SIMULTANEOUS_ASSIGNMENT |
#endif
#ifdef SPIDER_SQL_MODE_TIME_ROUND_FRACTIONAL
  MODE_TIME_ROUND_FRACTIONAL |
#endif
  0;

int spider_db_mbase_util::append_sql_mode_internal(
  spider_string *str,
  sql_mode_t sql_mode
) {
  DBUG_ENTER("spider_db_mbase_util::append_sql_mode_internal");
  DBUG_PRINT("info",("spider this=%p", this));
#ifdef SPIDER_SQL_MODE_REAL_AS_FLOAT
  if (sql_mode & MODE_REAL_AS_FLOAT)
  {
    if (str->reserve(SPIDER_REAL_AS_FLOAT_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_REAL_AS_FLOAT_STR, SPIDER_REAL_AS_FLOAT_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_PIPES_AS_CONCAT
  if (sql_mode & MODE_PIPES_AS_CONCAT)
  {
    if (str->reserve(SPIDER_PIPES_AS_CONCAT_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_PIPES_AS_CONCAT_STR, SPIDER_PIPES_AS_CONCAT_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_ANSI_QUOTES
  if (sql_mode & MODE_ANSI_QUOTES)
  {
    if (str->reserve(SPIDER_ANSI_QUOTES_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_ANSI_QUOTES_STR, SPIDER_ANSI_QUOTES_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_IGNORE_SPACE
  if (sql_mode & MODE_IGNORE_SPACE)
  {
    if (str->reserve(SPIDER_IGNORE_SPACE_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_IGNORE_SPACE_STR, SPIDER_IGNORE_SPACE_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_IGNORE_BAD_TABLE_OPTIONS
  if (sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS)
  {
    if (str->reserve(SPIDER_IGNORE_BAD_TABLE_OPTIONS_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_IGNORE_BAD_TABLE_OPTIONS_STR, SPIDER_IGNORE_BAD_TABLE_OPTIONS_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_ONLY_FULL_GROUP_BY
  if (sql_mode & MODE_ONLY_FULL_GROUP_BY)
  {
    if (str->reserve(SPIDER_ONLY_FULL_GROUP_BY_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_ONLY_FULL_GROUP_BY_STR, SPIDER_ONLY_FULL_GROUP_BY_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_UNSIGNED_SUBTRACTION
  if (sql_mode & MODE_NO_UNSIGNED_SUBTRACTION)
  {
    if (str->reserve(SPIDER_NO_UNSIGNED_SUBTRACTION_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_UNSIGNED_SUBTRACTION_STR, SPIDER_NO_UNSIGNED_SUBTRACTION_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_DIR_IN_CREATE
  if (sql_mode & MODE_NO_DIR_IN_CREATE)
  {
    if (str->reserve(SPIDER_NO_DIR_IN_CREATE_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_DIR_IN_CREATE_STR, SPIDER_NO_DIR_IN_CREATE_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_POSTGRESQL
  if (sql_mode & MODE_POSTGRESQL)
  {
    if (str->reserve(SPIDER_POSTGRESQL_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_POSTGRESQL_STR, SPIDER_POSTGRESQL_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_ORACLE
  if (sql_mode & MODE_ORACLE)
  {
    if (str->reserve(SPIDER_ORACLE_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_ORACLE_STR, SPIDER_ORACLE_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_MSSQL
  if (sql_mode & MODE_MSSQL)
  {
    if (str->reserve(SPIDER_MSSQL_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_MSSQL_STR, SPIDER_MSSQL_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_DB2
  if (sql_mode & MODE_DB2)
  {
    if (str->reserve(SPIDER_DB2_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_DB2_STR, SPIDER_DB2_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_MAXDB
  if (sql_mode & MODE_MAXDB)
  {
    if (str->reserve(SPIDER_MAXDB_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_MAXDB_STR, SPIDER_MAXDB_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_KEY_OPTIONS
  if (sql_mode & MODE_NO_KEY_OPTIONS)
  {
    if (str->reserve(SPIDER_NO_KEY_OPTIONS_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_KEY_OPTIONS_STR, SPIDER_NO_KEY_OPTIONS_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_TABLE_OPTIONS
  if (sql_mode & MODE_NO_TABLE_OPTIONS)
  {
    if (str->reserve(SPIDER_NO_TABLE_OPTIONS_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_TABLE_OPTIONS_STR, SPIDER_NO_TABLE_OPTIONS_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_FIELD_OPTIONS
  if (sql_mode & MODE_NO_FIELD_OPTIONS)
  {
    if (str->reserve(SPIDER_NO_FIELD_OPTIONS_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_FIELD_OPTIONS_STR, SPIDER_NO_FIELD_OPTIONS_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_MYSQL323
  if (sql_mode & MODE_MYSQL323)
  {
    if (str->reserve(SPIDER_MYSQL323_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_MYSQL323_STR, SPIDER_MYSQL323_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_MYSQL40
  if (sql_mode & MODE_MYSQL40)
  {
    if (str->reserve(SPIDER_MYSQL40_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_MYSQL40_STR, SPIDER_MYSQL40_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_ANSI
  if (sql_mode & MODE_ANSI)
  {
    if (str->reserve(SPIDER_ANSI_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_ANSI_STR, SPIDER_ANSI_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_AUTO_VALUE_ON_ZERO
  if (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
  {
    if (str->reserve(SPIDER_NO_AUTO_VALUE_ON_ZERO_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_AUTO_VALUE_ON_ZERO_STR, SPIDER_NO_AUTO_VALUE_ON_ZERO_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_BACKSLASH_ESCAPES
  if (sql_mode & MODE_NO_BACKSLASH_ESCAPES)
  {
    if (str->reserve(SPIDER_NO_BACKSLASH_ESCAPES_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_BACKSLASH_ESCAPES_STR, SPIDER_NO_BACKSLASH_ESCAPES_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_STRICT_TRANS_TABLES
  if (sql_mode & MODE_STRICT_TRANS_TABLES)
  {
    if (str->reserve(SPIDER_STRICT_TRANS_TABLES_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_STRICT_TRANS_TABLES_STR, SPIDER_STRICT_TRANS_TABLES_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_STRICT_ALL_TABLES
  if (sql_mode & MODE_STRICT_ALL_TABLES)
  {
    if (str->reserve(SPIDER_STRICT_ALL_TABLES_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_STRICT_ALL_TABLES_STR, SPIDER_STRICT_ALL_TABLES_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_ZERO_IN_DATE
  if (sql_mode & MODE_NO_ZERO_IN_DATE)
  {
    if (str->reserve(SPIDER_NO_ZERO_IN_DATE_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_ZERO_IN_DATE_STR, SPIDER_NO_ZERO_IN_DATE_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_ZERO_DATE
  if (sql_mode & MODE_NO_ZERO_DATE)
  {
    if (str->reserve(SPIDER_NO_ZERO_DATE_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_ZERO_DATE_STR, SPIDER_NO_ZERO_DATE_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_INVALID_DATES
  if (sql_mode & MODE_INVALID_DATES)
  {
    if (str->reserve(SPIDER_INVALID_DATES_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_INVALID_DATES_STR, SPIDER_INVALID_DATES_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_ERROR_FOR_DIVISION_BY_ZERO
  if (sql_mode & MODE_ERROR_FOR_DIVISION_BY_ZERO)
  {
    if (str->reserve(SPIDER_ERROR_FOR_DIVISION_BY_ZERO_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_ERROR_FOR_DIVISION_BY_ZERO_STR, SPIDER_ERROR_FOR_DIVISION_BY_ZERO_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_TRADITIONAL
  if (sql_mode & MODE_TRADITIONAL)
  {
    if (str->reserve(SPIDER_TRADITIONAL_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_TRADITIONAL_STR, SPIDER_TRADITIONAL_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_AUTO_CREATE_USER
  if (sql_mode & MODE_NO_AUTO_CREATE_USER)
  {
    if (str->reserve(SPIDER_NO_AUTO_CREATE_USER_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_AUTO_CREATE_USER_STR, SPIDER_NO_AUTO_CREATE_USER_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_HIGH_NOT_PRECEDENCE
  if (sql_mode & MODE_HIGH_NOT_PRECEDENCE)
  {
    if (str->reserve(SPIDER_HIGH_NOT_PRECEDENCE_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_HIGH_NOT_PRECEDENCE_STR, SPIDER_HIGH_NOT_PRECEDENCE_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_NO_ENGINE_SUBSTITUTION
  if (sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
  {
    if (str->reserve(SPIDER_NO_ENGINE_SUBSTITUTION_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_NO_ENGINE_SUBSTITUTION_STR, SPIDER_NO_ENGINE_SUBSTITUTION_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_PAD_CHAR_TO_FULL_LENGTH
  if (sql_mode & MODE_PAD_CHAR_TO_FULL_LENGTH)
  {
    if (str->reserve(SPIDER_PAD_CHAR_TO_FULL_LENGTH_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_PAD_CHAR_TO_FULL_LENGTH_STR, SPIDER_PAD_CHAR_TO_FULL_LENGTH_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
  DBUG_RETURN(0);
}

int spider_db_mariadb_util::append_sql_mode_internal(
  spider_string *str,
  sql_mode_t sql_mode
) {
  int error_num;
  DBUG_ENTER("spider_db_mbase_util::append_sql_mode_internal");
  DBUG_PRINT("info",("spider this=%p", this));
  if ((error_num = spider_db_mbase_util::append_sql_mode_internal(
    str, sql_mode)))
  {
    DBUG_RETURN(error_num);
  }
#ifdef SPIDER_SQL_MODE_EMPTY_STRING_IS_NULL
  if (sql_mode & MODE_EMPTY_STRING_IS_NULL)
  {
    if (str->reserve(SPIDER_EMPTY_STRING_IS_NULL_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_EMPTY_STRING_IS_NULL_STR, SPIDER_EMPTY_STRING_IS_NULL_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_SIMULTANEOUS_ASSIGNMENT
  if (sql_mode & MODE_SIMULTANEOUS_ASSIGNMENT)
  {
    if (str->reserve(SPIDER_SIMULTANEOUS_ASSIGNMENT_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SIMULTANEOUS_ASSIGNMENT_STR, SPIDER_SIMULTANEOUS_ASSIGNMENT_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
#ifdef SPIDER_SQL_MODE_TIME_ROUND_FRACTIONAL
  if (sql_mode & MODE_TIME_ROUND_FRACTIONAL)
  {
    if (str->reserve(SPIDER_TIME_ROUND_FRACTIONAL_LEN + SPIDER_SQL_COMMA_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_TIME_ROUND_FRACTIONAL_STR, SPIDER_TIME_ROUND_FRACTIONAL_LEN);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
#endif
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_sql_mode(
  spider_string *str,
  sql_mode_t sql_mode
) {
  int error_num;
  uint length;
  DBUG_ENTER("spider_db_mbase_util::append_sql_mode");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SEMICOLON_LEN + SPIDER_SQL_SQL_MODE_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  if (str->length())
  {
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }
  str->q_append(SPIDER_SQL_SQL_MODE_STR, SPIDER_SQL_SQL_MODE_LEN);
  length = str->length();
  if ((error_num = append_sql_mode_internal(str, sql_mode)))
  {
    DBUG_RETURN(error_num);
  }
  if (str->length() > length)
  {
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  } else {
    if (str->reserve(SPIDER_SQL_VALUE_QUOTE_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
  }
  str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  DBUG_RETURN(0);
}

/** Append `set session time_zone = ...` to a query string */
int spider_db_mbase_util::append_time_zone(
  spider_string *str,
  Time_zone *time_zone
) {
  const String *tz_str = time_zone->get_name();
  DBUG_ENTER("spider_db_mbase_util::append_time_zone");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SEMICOLON_LEN + SPIDER_SQL_TIME_ZONE_LEN +
    tz_str->length() + SPIDER_SQL_VALUE_QUOTE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  if (str->length())
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  str->q_append(SPIDER_SQL_TIME_ZONE_STR, SPIDER_SQL_TIME_ZONE_LEN);
  str->q_append(tz_str->ptr(), tz_str->length());
  str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  DBUG_RETURN(0);
}

/**
  Append a query for self-referencing check

  The query is setting a user variable `@spider_lc$target_table_path`
  to the value of `"$spider_unique_id$spider_table_path-"`, where
  $target_table_path is the path to the data node table ("to"), and
  $spider_table_path the path to the spider table ("from")


  iterate over loop_check_queue and build queries for loop check

  The query is in the form of

  set @`spider_lc_.<to_table>` =
  '-<mac1>-<pid1>-<from_table1>--<mac2>-<pid2>-<from_table2>-...'

  where from_table1, from_table2 etc. are spider tables whose direct
  or indirect remote data nodes contain to_table.

  e.g. if t0->t1->t2, then the query could be:

  set @`spider_lc_./test/t2` =
  '-234567890abc-def012-./test/t1--1234567890ab-cdef01-./test/t0-'
  */
int spider_db_mbase_util::append_loop_check(
  spider_string *str,
  SPIDER_CONN *conn
) {
  SPIDER_CONN_LOOP_CHECK *lcptr;
  DBUG_ENTER("spider_db_mbase_util::append_loop_check");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider str=%s", str->c_ptr_safe()));
  uint l = 0;
  while ((lcptr = (SPIDER_CONN_LOOP_CHECK *) my_hash_element(
    &conn->loop_check_queue, l)))
  {
    DBUG_PRINT("info",("spider lcptr=%p", lcptr));
    if (str->reserve(SPIDER_SQL_SEMICOLON_LEN + SPIDER_SQL_SET_USER_VAL_LEN +
      SPIDER_SQL_LOP_CHK_PRM_PRF_LEN + lcptr->to_name.length +
      SPIDER_SQL_NAME_QUOTE_LEN + SPIDER_SQL_EQUAL_LEN +
      SPIDER_SQL_VALUE_QUOTE_LEN +
      lcptr->merged_value.length + SPIDER_SQL_VALUE_QUOTE_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    if (str->length())
    {
      str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
    }
    str->q_append(SPIDER_SQL_SET_USER_VAL_STR, SPIDER_SQL_SET_USER_VAL_LEN);
    str->q_append(SPIDER_SQL_LOP_CHK_PRM_PRF_STR,
      SPIDER_SQL_LOP_CHK_PRM_PRF_LEN);
    str->q_append(lcptr->to_name.str, lcptr->to_name.length);
    str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    str->q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(lcptr->merged_value.str, lcptr->merged_value.length);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);

    ++l;
    DBUG_PRINT("info",("spider str=%s", str->c_ptr_safe()));
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_start_transaction(
  spider_string *str
) {
  DBUG_ENTER("spider_db_mbase_util::append_start_transaction");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SEMICOLON_LEN +
    SPIDER_SQL_START_TRANSACTION_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  if (str->length())
  {
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }
  str->q_append(SPIDER_SQL_START_TRANSACTION_STR,
    SPIDER_SQL_START_TRANSACTION_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_xa_start(
  spider_string *str,
  XID *xid
) {
  DBUG_ENTER("spider_db_mbase_util::append_xa_start");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SEMICOLON_LEN +
    SPIDER_SQL_XA_START_LEN + XIDDATASIZE + sizeof(long) + 9))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  if (str->length())
  {
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }
  str->q_append(SPIDER_SQL_XA_START_STR, SPIDER_SQL_XA_START_LEN);
  spider_db_append_xid_str(str, xid);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_lock_table_head(
  spider_string *str
) {
  DBUG_ENTER("spider_db_mbase_util::append_lock_table_head");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_LOCK_TABLE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_LOCK_TABLE_STR, SPIDER_SQL_LOCK_TABLE_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_lock_table_body(
  spider_string *str,
  const char *db_name,
  uint db_name_length,
  CHARSET_INFO *db_name_charset,
  const char *table_name,
  uint table_name_length,
  CHARSET_INFO *table_name_charset,
  int lock_type
) {
  DBUG_ENTER("spider_db_mbase_util::append_lock_table_body");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_NAME_QUOTE_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  if (
    str->append(db_name, db_name_length, db_name_charset) ||
    str->reserve((SPIDER_SQL_NAME_QUOTE_LEN) * 2 + SPIDER_SQL_DOT_LEN)
  ) {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  str->q_append(SPIDER_SQL_DOT_STR, SPIDER_SQL_DOT_LEN);
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  if (
    str->append(table_name, table_name_length, table_name_charset) ||
    str->reserve(SPIDER_SQL_NAME_QUOTE_LEN +
      spider_db_table_lock_len[lock_type])
  ) {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  str->q_append(spider_db_table_lock_str[lock_type],
    spider_db_table_lock_len[lock_type]);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_lock_table_tail(
  spider_string *str
) {
  DBUG_ENTER("spider_db_mbase_util::append_lock_table_tail");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_unlock_table(
  spider_string *str
) {
  DBUG_ENTER("spider_db_mbase_util::append_unlock_table");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_UNLOCK_TABLE_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_UNLOCK_TABLE_STR, SPIDER_SQL_UNLOCK_TABLE_LEN);
  DBUG_RETURN(0);
}

/**
  The function check if the given item_func and its arguments can be pushed
  down to a data node. If so and str != NULL, the function also print, to str,
  the string corresponding to the item_func.

  @return 0: success, otherwise: error
 */
int spider_db_mbase_util::open_item_func(
  Item_func *item_func,
  ha_spider *spider,
  spider_string *str,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields
) {
  DBUG_ENTER("spider_db_mbase_util::open_item_func");

  if (!str)
    DBUG_RETURN(check_item_func(item_func, spider, alias,
                                alias_length, use_fields, fields));
  DBUG_RETURN(print_item_func(item_func, spider, str, alias,
    alias_length, use_fields, fields));
}

static bool not_func_should_be_skipped(
  Item_func *item_func
){
  DBUG_ENTER("not_func_should_be_skipped");
  DBUG_ASSERT(item_func->functype() == Item_func::NOT_FUNC);
  Item **item_list = item_func->arguments();

  if (item_list[0]->type() == Item::COND_ITEM)
  {
    DBUG_PRINT("info",("spider item_list[0] is COND_ITEM"));
    Item_cond *item_cond = (Item_cond *) item_list[0];
    if (item_cond->functype() == Item_func::COND_AND_FUNC)
    {
      DBUG_PRINT("info",("spider item_cond is COND_AND_FUNC"));
      List_iterator_fast<Item> lif(*(item_cond->argument_list()));
      bool has_expr_cache_item = FALSE;
      bool has_isnotnull_func = FALSE;
      bool has_other_item = FALSE;
      while(Item *item = lif++)
      {
        if (
          item->type() == Item::EXPR_CACHE_ITEM
        ) {
          DBUG_PRINT("info",("spider EXPR_CACHE_ITEM"));
          has_expr_cache_item = TRUE;
        } else
        if (
          item->type() == Item::FUNC_ITEM &&
          ((Item_func *) item)->functype() == Item_func::ISNOTNULL_FUNC
        ) {
          DBUG_PRINT("info",("spider ISNOTNULL_FUNC"));
          has_isnotnull_func = TRUE;
        } else {
          DBUG_PRINT("info",("spider has other item"));
          DBUG_PRINT("info",("spider COND type=%d", item->type()));
          has_other_item = TRUE;
        }
      }
      if (has_expr_cache_item && has_isnotnull_func && !has_other_item)
      {
        DBUG_PRINT("info",("spider NOT EXISTS skip"));
        DBUG_RETURN(TRUE);
      }
    }
  }
  DBUG_RETURN(FALSE);
}

/**
  Check if the given item_func and its arguments can be pushed down to
  a data node. This function is recursive because we need to also check
  the arguments of the item_func.

  @return 0: success, otherwise: error
 */
int spider_db_mbase_util::check_item_func(
  Item_func *item_func,
  ha_spider *spider,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields
) {
  int use_pushdown_udf;
  DBUG_ENTER("spider_db_mbase_util::check_item_func");

  Item_func::Functype func_type = item_func->functype();
  DBUG_PRINT("info",("spider functype = %d", func_type));

  /* The blacklist of the functions that cannot be pushed down */
  switch (func_type)
  {
    case Item_func::TRIG_COND_FUNC:
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    case Item_func::NOT_FUNC:
      /* Why the following check is necessary? */
      if (not_func_should_be_skipped(item_func))
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      break;
    case Item_func::FUNC_SP:
    case Item_func::UDF_FUNC:
      use_pushdown_udf= spider_param_use_pushdown_udf(
          spider->wide_handler->trx->thd, spider->share->use_pushdown_udf);
      if (!use_pushdown_udf)
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      break;
    case Item_func::FT_FUNC:
      if (spider_db_check_ft_idx(item_func, spider) == MAX_KEY)
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      break;
    case Item_func::MULT_EQUAL_FUNC:
      /* If there is still Item_equal by the time of
      JOIN::make_aggr_tables_info() where the spider group by handler
      is created, it indicates a bug in the optimizer, because there
      shouldn't be any. */
      push_warning_printf(
        spider->wide_handler->trx->thd, SPIDER_WARN_LEVEL_WARN,
        ER_INTERNAL_ERROR,
        ER_THD(spider->wide_handler->trx->thd, ER_INTERNAL_ERROR),
        "Spider group by handler: Encountered multiple equalities, likely "
        "an optimizer bug");
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    default:
      break;
  }
  /* End of the blacklist */

  /* Check the arguments recursively */
  if (uint item_count = item_func->argument_count())
  {
    Item **item_list = item_func->arguments();
    for (uint roop_count = 0; roop_count < item_count; roop_count++)
    {
      Item *item = item_list[roop_count];
      if (int error_num = spider_db_print_item_type(item, NULL, spider, NULL,
        alias, alias_length, dbton_id, use_fields, fields))
        DBUG_RETURN(error_num);
    }
  }

  DBUG_RETURN(0);
}

/**
  The function print the string corresponding to the given item_func to str.
  The function is assumed to be called only when the check by the function
  check_item_func() has passed.

  @return 0: success, otherwise: error
 */
int spider_db_mbase_util::print_item_func(
  Item_func *item_func,
  ha_spider *spider,
  spider_string *str,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields
) {
  int error_num;
  Item *item, **item_list = item_func->arguments();
  Field *field;
  spider_string tmp_str;
  uint i, item_count = item_func->argument_count(), start_item = 0;
  LEX_CSTRING org_func_name= {SPIDER_SQL_NULL_CHAR_STR,
                              SPIDER_SQL_NULL_CHAR_LEN};
  const char *func_name = SPIDER_SQL_NULL_CHAR_STR,
    *separator_str = SPIDER_SQL_NULL_CHAR_STR,
    *last_str = SPIDER_SQL_NULL_CHAR_STR;
  int func_name_length = SPIDER_SQL_NULL_CHAR_LEN,
    separator_str_length = SPIDER_SQL_NULL_CHAR_LEN,
    last_str_length = SPIDER_SQL_NULL_CHAR_LEN;
  int use_pushdown_udf, case_when_start, case_when_count;
  bool merge_func = FALSE, case_with_else;
  DBUG_ENTER("spider_db_mbase_util::print_item_func");
  DBUG_ASSERT(str);

  if (str->reserve(SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);

  DBUG_PRINT("info",("spider functype = %d", item_func->functype()));
  switch (item_func->functype())
  {
    case Item_func::ISNULL_FUNC:
      last_str = SPIDER_SQL_IS_NULL_STR;
      last_str_length = SPIDER_SQL_IS_NULL_LEN;
      break;
    case Item_func::ISNOTNULL_FUNC:
      last_str = SPIDER_SQL_IS_NOT_NULL_STR;
      last_str_length = SPIDER_SQL_IS_NOT_NULL_LEN;
      break;
    case Item_func::LEFT_FUNC:
    case Item_func::SUBSTR_FUNC:
    case Item_func::UNKNOWN_FUNC:
      org_func_name= item_func->func_name_cstring();
      func_name= org_func_name.str;
      func_name_length = org_func_name.length;
      DBUG_PRINT("info",("spider func_name = %s", func_name));
      DBUG_PRINT("info",("spider func_name_length = %d", func_name_length));
      if (func_name_length == 1 &&
        (
          !strncasecmp("+", func_name, func_name_length) ||
          !strncasecmp("-", func_name, func_name_length) ||
          !strncasecmp("*", func_name, func_name_length) ||
          !strncasecmp("/", func_name, func_name_length) ||
          !strncasecmp("%", func_name, func_name_length) ||
          !strncasecmp("&", func_name, func_name_length) ||
          !strncasecmp("|", func_name, func_name_length) ||
          !strncasecmp("^", func_name, func_name_length)
        )
      ) {
        /* no action */
        break;
      } else if (func_name_length == 2 &&
        (
          !strncasecmp("<<", func_name, func_name_length) ||
          !strncasecmp(">>", func_name, func_name_length)
        )
      ) {
        /* no action */
        break;
      } else if (func_name_length == 3 &&
        !strncasecmp("div", func_name, func_name_length)
      ) {
        /* no action */
        break;
      } else if (func_name_length == 4)
      {
        if (
          !strncasecmp("rand", func_name, func_name_length) &&
          !item_func->argument_count()
        ) {
          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          DBUG_RETURN(spider_db_open_item_int(item_func, NULL, spider, str,
            alias, alias_length, dbton_id, use_fields, fields));
        } else if (
          !strncasecmp("trim", func_name, func_name_length) &&
          item_count == 2
        ) {
          /* item_count == 1 means this TRIM() is without a remove_str */
          item = item_list[0];
          Item *item_tmp = item_list[1];

          if (item_tmp->is_of_type(Item::CONST_ITEM, STRING_RESULT))
          {
            /* 1. append 'TRIM(BOTH ' */
            if (str->reserve(SPIDER_SQL_TRIM_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
                             SPIDER_SQL_TRIM_BOTH_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_TRIM_STR, SPIDER_SQL_TRIM_LEN);
            str->q_append(SPIDER_SQL_OPEN_PAREN_STR,
                          SPIDER_SQL_OPEN_PAREN_LEN);
            str->q_append(SPIDER_SQL_TRIM_BOTH_STR, SPIDER_SQL_TRIM_BOTH_LEN);
            /* 2. append "remove_str"*/
            if ((error_num = spider_db_print_item_type(
                    item_tmp, NULL, spider, str, alias, alias_length, dbton_id,
                    use_fields, fields)))
              DBUG_RETURN(error_num);
            /* 3. append ' FROM ' */
            if (str->reserve(SPIDER_SQL_FROM_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_FROM_STR, SPIDER_SQL_FROM_LEN);
            /* 4. append `field` */
            if ((error_num = spider_db_print_item_type(
                    item, NULL, spider, str, alias, alias_length, dbton_id,
                    use_fields, fields)))
              DBUG_RETURN(error_num);
            /* 5. append ')' */
            if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,
                          SPIDER_SQL_CLOSE_PAREN_LEN);
          }
          item_count -= 2;
          break;
        }
      } else if (func_name_length == 5)
      {
        if (
          (!strncasecmp("ltrim", func_name, func_name_length) ||
           !strncasecmp("rtrim", func_name, func_name_length)) &&
          (item_count == 2)
        ) {
          /* the func_name for TRIM(LEADING ...) is LTRIM, for TRIM(TRAILING) is RTRIM */
          /* item_count == 2 means this TRIM(LEADING/TRAILING ...) is with a remove_str */
          item = item_list[0];
          Item *item_tmp = item_list[1];
          if (item_tmp->is_of_type(Item::CONST_ITEM, STRING_RESULT))
          {
            /* 1. append 'TRIM(LEADING ' or 'TRIM(TRAILING ' */
            if (func_name[0] == 'l' || func_name[0] == 'L')
            { /* ltrim */
              if (str->reserve(SPIDER_SQL_TRIM_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
                               SPIDER_SQL_TRIM_LEADING_LEN))
                DBUG_RETURN(HA_ERR_OUT_OF_MEM);
              str->q_append(SPIDER_SQL_TRIM_STR, SPIDER_SQL_TRIM_LEN);
              str->q_append(SPIDER_SQL_OPEN_PAREN_STR,
                            SPIDER_SQL_OPEN_PAREN_LEN);
              str->q_append(SPIDER_SQL_TRIM_LEADING_STR, SPIDER_SQL_TRIM_LEADING_LEN);
            } else
            { /* rtrim */
              if (str->reserve(SPIDER_SQL_TRIM_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
                               SPIDER_SQL_TRIM_TRAILING_LEN))
                DBUG_RETURN(HA_ERR_OUT_OF_MEM);
              str->q_append(SPIDER_SQL_TRIM_STR, SPIDER_SQL_TRIM_LEN);
              str->q_append(SPIDER_SQL_OPEN_PAREN_STR,
                            SPIDER_SQL_OPEN_PAREN_LEN);
              str->q_append(SPIDER_SQL_TRIM_TRAILING_STR, SPIDER_SQL_TRIM_TRAILING_LEN);
            }
            /* 2. append "remove_str"*/
            if ((error_num = spider_db_print_item_type(
                item_tmp, NULL, spider, str, alias, alias_length, dbton_id,
                use_fields, fields)))
              DBUG_RETURN(error_num);
            /* 3. append ' FROM ' */
            if (str->reserve(SPIDER_SQL_FROM_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_FROM_STR, SPIDER_SQL_FROM_LEN);
            /* 4. append `field` */
            if ((error_num = spider_db_print_item_type(
                item, NULL, spider, str, alias, alias_length, dbton_id,
                use_fields, fields)))
              DBUG_RETURN(error_num);
            /* 5. append ')' */
            if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,
                          SPIDER_SQL_CLOSE_PAREN_LEN);
          }
          item_count -= 2;
          break;
        }
      } else if (func_name_length == 6)
      {
        if (!strncasecmp("istrue", func_name, func_name_length))
        {
          last_str= SPIDER_SQL_IS_TRUE_STR;
          last_str_length= SPIDER_SQL_IS_TRUE_LEN;
          break;
        }
        else if (!strncasecmp("regexp", func_name, func_name_length))
          /* Keep the infix expression */
          break;
      } else if (func_name_length == 7)
      {
        if (!strncasecmp("isfalse", func_name, func_name_length))
        {
          last_str = SPIDER_SQL_IS_FALSE_STR;
          last_str_length = SPIDER_SQL_IS_FALSE_LEN;
          break;
        } else if (
          !strncasecmp("sysdate", func_name, func_name_length) ||
          !strncasecmp("curdate", func_name, func_name_length) ||
          !strncasecmp("curtime", func_name, func_name_length)
        ) {
          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          DBUG_RETURN(spider_db_open_item_string(item_func, NULL, spider, str,
            alias, alias_length, dbton_id, use_fields, fields));
        } else if (
          !strncasecmp("convert", func_name, func_name_length)
        ) {
          if (str->reserve(func_name_length * 2 + SPIDER_SQL_OPEN_PAREN_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(func_name, func_name_length);
          str->q_append(SPIDER_SQL_OPEN_PAREN_STR,
            SPIDER_SQL_OPEN_PAREN_LEN);
          last_str = SPIDER_SQL_CLOSE_PAREN_STR;
          last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
          break;
        }
      } else if (func_name_length == 8 &&
        (
          !strncasecmp("utc_date", func_name, func_name_length) ||
          !strncasecmp("utc_time", func_name, func_name_length)
        )
      ) {
        str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
        DBUG_RETURN(spider_db_open_item_string(item_func, NULL, spider, str,
          alias, alias_length, dbton_id, use_fields, fields));
      } else if (func_name_length == 9 &&
        !strncasecmp("isnottrue", func_name, func_name_length)
      ) {
        last_str = SPIDER_SQL_IS_NOT_TRUE_STR;
        last_str_length = SPIDER_SQL_IS_NOT_TRUE_LEN;
        break;
      } else if (func_name_length == 10)
      {
        if (!strncasecmp("isnotfalse", func_name, func_name_length))
        {
          last_str = SPIDER_SQL_IS_NOT_FALSE_STR;
          last_str_length = SPIDER_SQL_IS_NOT_FALSE_LEN;
          break;
        } else if (!strncasecmp("column_get", func_name, func_name_length))
        {
          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (str->reserve(func_name_length + SPIDER_SQL_OPEN_PAREN_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(func_name, func_name_length);
          str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);

          func_name = SPIDER_SQL_COMMA_STR;
          func_name_length = SPIDER_SQL_COMMA_LEN;
          separator_str = SPIDER_SQL_COMMA_STR;
          separator_str_length = SPIDER_SQL_COMMA_LEN;
          break;
        }
      } else if (func_name_length == 12)
      {
        if (!strncasecmp("cast_as_date", func_name, func_name_length))
        {
          item = item_list[0];
          if (item->type() == Item::FUNC_ITEM)
          {
            DBUG_PRINT("info",("spider child is FUNC_ITEM"));
            Item_func *ifunc = (Item_func *) item;
            if (ifunc->functype() == Item_func::UNKNOWN_FUNC)
            {
              const char *child_func_name;
              int child_func_name_length;
              LEX_CSTRING org_func_name= ifunc->func_name_cstring();
              DBUG_PRINT("info",("spider child is UNKNOWN_FUNC"));
              child_func_name = org_func_name.str;
              child_func_name_length =  org_func_name.length;
              DBUG_PRINT("info",("spider child func_name is %s", child_func_name));
              if (
                child_func_name_length == 10 &&
                !strncasecmp("column_get", child_func_name, child_func_name_length)
              ) {
                DBUG_PRINT("info",("spider this is merge func"));
                merge_func = TRUE;
              }
            }
          }

          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (!merge_func)
          {
            if (str->reserve(SPIDER_SQL_CAST_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
          }
          last_str = SPIDER_SQL_AS_DATE_STR;
          last_str_length = SPIDER_SQL_AS_DATE_LEN;
          break;
        } else if (!strncasecmp("cast_as_time", func_name, func_name_length))
        {
          item = item_list[0];
          if (item->type() == Item::FUNC_ITEM)
          {
            DBUG_PRINT("info",("spider child is FUNC_ITEM"));
            Item_func *ifunc = (Item_func *) item;
            if (ifunc->functype() == Item_func::UNKNOWN_FUNC)
            {
              const char *child_func_name;
              int child_func_name_length;
              LEX_CSTRING org_func_name= ifunc->func_name_cstring();
              DBUG_PRINT("info",("spider child is UNKNOWN_FUNC"));
              child_func_name = org_func_name.str;
              child_func_name_length =  org_func_name.length;
              DBUG_PRINT("info",("spider child func_name is %s", child_func_name));
              if (
                child_func_name_length == 10 &&
                !strncasecmp("column_get", child_func_name, child_func_name_length)
              ) {
                DBUG_PRINT("info",("spider this is merge func"));
                merge_func = TRUE;
              }
            }
          }

          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (!merge_func)
          {
            if (str->reserve(SPIDER_SQL_CAST_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
          }
          last_str = SPIDER_SQL_AS_TIME_STR;
          last_str_length = SPIDER_SQL_AS_TIME_LEN;
          break;
        }
      } else if (func_name_length == 13)
      {
        if (!strncasecmp("utc_timestamp", func_name, func_name_length))
        {
          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          DBUG_RETURN(spider_db_open_item_string(item_func, NULL, spider, str,
            alias, alias_length, dbton_id, use_fields, fields));
        } else if (!strncasecmp("timestampdiff", func_name, func_name_length))
        {
          Item_func_timestamp_diff *item_func_timestamp_diff =
            (Item_func_timestamp_diff *) item_func;
          const char *interval_str;
          uint interval_len;
          switch (item_func_timestamp_diff->get_int_type())
          {
          case INTERVAL_YEAR:
            interval_str = SPIDER_SQL_YEAR_STR;
            interval_len = SPIDER_SQL_YEAR_LEN;
            break;
          case INTERVAL_QUARTER:
            interval_str = SPIDER_SQL_QUARTER_STR;
            interval_len = SPIDER_SQL_QUARTER_LEN;
            break;
          case INTERVAL_MONTH:
            interval_str = SPIDER_SQL_MONTH_STR;
            interval_len = SPIDER_SQL_MONTH_LEN;
            break;
          case INTERVAL_WEEK:
            interval_str = SPIDER_SQL_WEEK_STR;
            interval_len = SPIDER_SQL_WEEK_LEN;
            break;
          case INTERVAL_DAY:
            interval_str = SPIDER_SQL_DAY_STR;
            interval_len = SPIDER_SQL_DAY_LEN;
            break;
          case INTERVAL_HOUR:
            interval_str = SPIDER_SQL_HOUR_STR;
            interval_len = SPIDER_SQL_HOUR_LEN;
            break;
          case INTERVAL_MINUTE:
            interval_str = SPIDER_SQL_MINUTE_STR;
            interval_len = SPIDER_SQL_MINUTE_LEN;
            break;
          case INTERVAL_SECOND:
            interval_str = SPIDER_SQL_SECOND_STR;
            interval_len = SPIDER_SQL_SECOND_LEN;
            break;
          case INTERVAL_MICROSECOND:
            interval_str = SPIDER_SQL_MICROSECOND_STR;
            interval_len = SPIDER_SQL_MICROSECOND_LEN;
            break;
          default:
            interval_str = "";
            interval_len = 0;
            break;
          }
          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (str->reserve(func_name_length + SPIDER_SQL_OPEN_PAREN_LEN +
                           interval_len + SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(func_name, func_name_length);
          str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
          str->q_append(interval_str, interval_len);
          str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);

          if ((error_num = spider_db_print_item_type(item_list[0], NULL, spider,
                                                     str, alias, alias_length, dbton_id, use_fields, fields)))
            DBUG_RETURN(error_num);
          if (str)
          {
            if (str->reserve(SPIDER_SQL_COMMA_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
          }
          if ((error_num = spider_db_print_item_type(item_list[1], NULL, spider,
                                                     str, alias, alias_length, dbton_id, use_fields, fields)))
            DBUG_RETURN(error_num);
          if (str)
          {
            if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,
                          SPIDER_SQL_CLOSE_PAREN_LEN);
          }
          DBUG_RETURN(0);
        }
      } else if (func_name_length == 14)
      {
        if (!strncasecmp("cast_as_binary", func_name, func_name_length))
        {
          item = item_list[0];
          if (item->type() == Item::FUNC_ITEM)
          {
            DBUG_PRINT("info",("spider child is FUNC_ITEM"));
            Item_func *ifunc = (Item_func *) item;
            if (ifunc->functype() == Item_func::UNKNOWN_FUNC)
            {
              const char *child_func_name;
              int child_func_name_length;
              LEX_CSTRING org_func_name= ifunc->func_name_cstring();
              DBUG_PRINT("info",("spider child is UNKNOWN_FUNC"));
              child_func_name = org_func_name.str;
              child_func_name_length =  org_func_name.length;
              DBUG_PRINT("info",("spider child func_name is %s", child_func_name));
              if (
                child_func_name_length == 10 &&
                !strncasecmp("column_get", child_func_name, child_func_name_length)
              ) {
                DBUG_PRINT("info",("spider this is merge func"));
                merge_func = TRUE;
              }
            }
          }

          char *tmp_ptr, *tmp_ptr2;
          DBUG_ASSERT(tmp_str.length() == 0);
          tmp_str.set_charset(str->charset());
          tmp_str.init_calc_mem(SPD_MID_DB_MBASE_UTIL_PRINT_ITEM_FUNC_1);
          tmp_str.reserve(MAX_FIELD_WIDTH);
          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (!merge_func)
          {
            if (str->reserve(SPIDER_SQL_CAST_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
          }
          item_func->print(tmp_str.get_str(), QT_TO_SYSTEM_CHARSET);
          tmp_str.mem_calc();
          if (tmp_str.reserve(1))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          last_str = tmp_ptr = tmp_str.c_ptr_quick();
          DBUG_PRINT("info",("spider tmp_ptr = %s", tmp_ptr));
          while ((tmp_ptr2 = strstr(tmp_ptr, SPIDER_SQL_AS_BINARY_STR)))
            tmp_ptr = tmp_ptr2 + 1;
          if (tmp_ptr != last_str)
            last_str = tmp_ptr - 1;
          last_str_length = strlen(last_str) - SPIDER_SQL_CLOSE_PAREN_LEN;
          break;
        } else if (!strncasecmp("cast_as_signed", func_name, func_name_length))
        {
          item = item_list[0];
          if (item->type() == Item::FUNC_ITEM)
          {
            DBUG_PRINT("info",("spider child is FUNC_ITEM"));
            Item_func *ifunc = (Item_func *) item;
            if (ifunc->functype() == Item_func::UNKNOWN_FUNC)
            {
              const char *child_func_name;
              int child_func_name_length;
              LEX_CSTRING org_func_name= ifunc->func_name_cstring();
              DBUG_PRINT("info",("spider child is UNKNOWN_FUNC"));
              child_func_name = org_func_name.str;
              child_func_name_length =  org_func_name.length;
              DBUG_PRINT("info",("spider child func_name is %s", child_func_name));
              if (
                child_func_name_length == 10 &&
                !strncasecmp("column_get", child_func_name, child_func_name_length)
              ) {
                DBUG_PRINT("info",("spider this is merge func"));
                merge_func = TRUE;
              }
            }
          }

          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (!merge_func)
          {
            if (str->reserve(SPIDER_SQL_CAST_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
          }
          last_str = SPIDER_SQL_AS_SIGNED_STR;
          last_str_length = SPIDER_SQL_AS_SIGNED_LEN;
          break;
        }
      } else if (func_name_length == 16)
      {
        if (!strncasecmp("cast_as_unsigned", func_name, func_name_length))
        {
          item = item_list[0];
          if (item->type() == Item::FUNC_ITEM)
          {
            DBUG_PRINT("info",("spider child is FUNC_ITEM"));
            Item_func *ifunc = (Item_func *) item;
            if (ifunc->functype() == Item_func::UNKNOWN_FUNC)
            {
              const char *child_func_name;
              int child_func_name_length;
              LEX_CSTRING org_func_name= ifunc->func_name_cstring();
              DBUG_PRINT("info",("spider child is UNKNOWN_FUNC"));
              child_func_name = org_func_name.str;
              child_func_name_length =  org_func_name.length;
              DBUG_PRINT("info",("spider child func_name is %s", child_func_name));
              if (
                child_func_name_length == 10 &&
                !strncasecmp("column_get", child_func_name, child_func_name_length)
              ) {
                DBUG_PRINT("info",("spider this is merge func"));
                merge_func = TRUE;
              }
            }
          }

          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (!merge_func)
          {
            if (str->reserve(SPIDER_SQL_CAST_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
          }
          last_str = SPIDER_SQL_AS_UNSIGNED_STR;
          last_str_length = SPIDER_SQL_AS_UNSIGNED_LEN;
          break;
        } else if (!strncasecmp("decimal_typecast", func_name,
          func_name_length))
        {
          item = item_list[0];
          if (item->type() == Item::FUNC_ITEM)
          {
            DBUG_PRINT("info",("spider child is FUNC_ITEM"));
            Item_func *ifunc = (Item_func *) item;
            if (ifunc->functype() == Item_func::UNKNOWN_FUNC)
            {
              const char *child_func_name;
              int child_func_name_length;
              LEX_CSTRING org_func_name= ifunc->func_name_cstring();
              DBUG_PRINT("info",("spider child is UNKNOWN_FUNC"));
              child_func_name = org_func_name.str;
              child_func_name_length =  org_func_name.length;
              DBUG_PRINT("info",("spider child func_name is %s", child_func_name));
              if (
                child_func_name_length == 10 &&
                !strncasecmp("column_get", child_func_name, child_func_name_length)
              ) {
                DBUG_PRINT("info",("spider this is merge func"));
                merge_func = TRUE;
              }
            }
          }

          char *tmp_ptr, *tmp_ptr2;
          DBUG_ASSERT(tmp_str.length() == 0);
          tmp_str.set_charset(str->charset());
          tmp_str.init_calc_mem(SPD_MID_DB_MBASE_UTIL_PRINT_ITEM_FUNC_2);
          tmp_str.reserve(MAX_FIELD_WIDTH);
          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (!merge_func)
          {
            if (str->reserve(SPIDER_SQL_CAST_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
          }
          item_func->print(tmp_str.get_str(), QT_TO_SYSTEM_CHARSET);
          tmp_str.mem_calc();
          if (tmp_str.reserve(1))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          last_str = tmp_ptr = tmp_str.c_ptr_quick();
          DBUG_PRINT("info",("spider tmp_ptr = %s", tmp_ptr));
          while ((tmp_ptr2 = strstr(tmp_ptr, SPIDER_SQL_AS_DECIMAL_STR)))
            tmp_ptr = tmp_ptr2 + 1;
          if (tmp_ptr != last_str)
            last_str = tmp_ptr - 1;
          last_str_length = strlen(last_str) - SPIDER_SQL_CLOSE_PAREN_LEN;
          break;
        } else if (!strncasecmp("cast_as_datetime", func_name,
          func_name_length))
        {
          item = item_list[0];
          if (item->type() == Item::FUNC_ITEM)
          {
            DBUG_PRINT("info",("spider child is FUNC_ITEM"));
            Item_func *ifunc = (Item_func *) item;
            if (ifunc->functype() == Item_func::UNKNOWN_FUNC)
            {
              const char *child_func_name;
              int child_func_name_length;
              LEX_CSTRING org_func_name= ifunc->func_name_cstring();
              DBUG_PRINT("info",("spider child is UNKNOWN_FUNC"));
              child_func_name = org_func_name.str;
              child_func_name_length =  org_func_name.length;
              DBUG_PRINT("info",("spider child func_name is %s", child_func_name));
              if (
                child_func_name_length == 10 &&
                !strncasecmp("column_get", child_func_name, child_func_name_length)
              ) {
                DBUG_PRINT("info",("spider this is merge func"));
                merge_func = TRUE;
              }
            }
          }

          str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
          if (!merge_func)
          {
            if (str->reserve(SPIDER_SQL_CAST_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
          }
          last_str = SPIDER_SQL_AS_DATETIME_STR;
          last_str_length = SPIDER_SQL_AS_DATETIME_LEN;
          break;
        }
      } else if (func_name_length == 17)
      {
        if (!strncasecmp("date_add_interval", func_name, func_name_length))
        {
          Item_date_add_interval *item_date_add_interval =
            (Item_date_add_interval *) item_func;
          func_name = spider_db_timefunc_interval_str[
            item_date_add_interval->int_type];
          func_name_length = strlen(func_name);
          if ((error_num = spider_db_print_item_type(item_list[0], NULL, spider,
            str, alias, alias_length, dbton_id, use_fields, fields)))
            DBUG_RETURN(error_num);
          if (item_date_add_interval->date_sub_interval)
          {
            if (str->reserve(SPIDER_SQL_NEGINTERVAL_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_NEGINTERVAL_STR,
              SPIDER_SQL_NEGINTERVAL_LEN);
          } else {
            if (str->reserve(SPIDER_SQL_INTERVAL_LEN))
              DBUG_RETURN(HA_ERR_OUT_OF_MEM);
            str->q_append(SPIDER_SQL_INTERVAL_STR, SPIDER_SQL_INTERVAL_LEN);
          }
          if ((error_num = spider_db_print_item_type(item_list[1], NULL, spider,
            str, alias, alias_length, dbton_id, use_fields, fields)))
            DBUG_RETURN(error_num);
          if (str->reserve(func_name_length + SPIDER_SQL_CLOSE_PAREN_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(func_name, func_name_length);
          str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,
            SPIDER_SQL_CLOSE_PAREN_LEN);
          DBUG_RETURN(0);
        }
      }
      if (str->reserve(func_name_length + SPIDER_SQL_OPEN_PAREN_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(func_name, func_name_length);
      str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
      func_name = SPIDER_SQL_COMMA_STR;
      func_name_length = SPIDER_SQL_COMMA_LEN;
      separator_str = SPIDER_SQL_COMMA_STR;
      separator_str_length = SPIDER_SQL_COMMA_LEN;
      last_str = SPIDER_SQL_CLOSE_PAREN_STR;
      last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
      break;
    case Item_func::NOW_FUNC:
      str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
      DBUG_RETURN(spider_db_open_item_string(item_func, NULL, spider,
        str, alias, alias_length, dbton_id, use_fields, fields));
    case Item_func::CHAR_TYPECAST_FUNC:
      DBUG_PRINT("info",("spider CHAR_TYPECAST_FUNC"));
      {
        item = item_list[0];
        if (item->type() == Item::FUNC_ITEM)
        {
          DBUG_PRINT("info",("spider child is FUNC_ITEM"));
          Item_func *ifunc = (Item_func *) item;
          if (ifunc->functype() == Item_func::UNKNOWN_FUNC)
          {
            const char *child_func_name;
            int child_func_name_length;
            LEX_CSTRING org_func_name= ifunc->func_name_cstring();
            DBUG_PRINT("info",("spider child is UNKNOWN_FUNC"));
            child_func_name = org_func_name.str;
            child_func_name_length =  org_func_name.length;
            DBUG_PRINT("info",("spider child func_name is %s", child_func_name));
            if (
              child_func_name_length == 10 &&
              !strncasecmp("column_get", child_func_name, child_func_name_length)
            ) {
              DBUG_PRINT("info",("spider this is merge func"));
              merge_func = TRUE;
            }
          }
        }

        char *tmp_ptr, *tmp_ptr2;
        DBUG_ASSERT(tmp_str.length() == 0);
        tmp_str.set_charset(str->charset());
        tmp_str.init_calc_mem(SPD_MID_DB_MBASE_UTIL_PRINT_ITEM_FUNC_3);
        tmp_str.reserve(MAX_FIELD_WIDTH);
        str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
        if (!merge_func)
        {
          if (str->reserve(SPIDER_SQL_CAST_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_CAST_STR, SPIDER_SQL_CAST_LEN);
        }
        item_func->print(tmp_str.get_str(), QT_TO_SYSTEM_CHARSET);
        tmp_str.mem_calc();
        if (tmp_str.reserve(1))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        last_str = tmp_ptr = tmp_str.c_ptr_quick();
        DBUG_PRINT("info",("spider tmp_ptr = %s", tmp_ptr));
        while ((tmp_ptr2 = strstr(tmp_ptr, SPIDER_SQL_AS_STR)))
          tmp_ptr = tmp_ptr2 + 1;
        if (tmp_ptr != last_str)
          last_str = tmp_ptr - 1;
        last_str_length = strlen(last_str) - SPIDER_SQL_CLOSE_PAREN_LEN;
      }
      break;
    case Item_func::NOT_FUNC:
      DBUG_PRINT("info",("spider NOT_FUNC"));
      /* Why the following check is necessary? */
      if (not_func_should_be_skipped(item_func))
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      {
        LEX_CSTRING org_func_name= item_func->func_name_cstring();
        func_name = org_func_name.str;
        func_name_length = org_func_name.length;
      }
      if (str->reserve(func_name_length + SPIDER_SQL_SPACE_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(func_name, func_name_length);
      str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
      break;
    case Item_func::NEG_FUNC:
      {
        LEX_CSTRING org_func_name= item_func->func_name_cstring();
        func_name = org_func_name.str;
        func_name_length = org_func_name.length;
      }
      if (str->reserve(func_name_length + SPIDER_SQL_SPACE_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(func_name, func_name_length);
      str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
      break;
    case Item_func::IN_FUNC:
      if (((Item_func_opt_neg *) item_func)->negated)
      {
        func_name = SPIDER_SQL_NOT_IN_STR;
        func_name_length = SPIDER_SQL_NOT_IN_LEN;
        separator_str = SPIDER_SQL_COMMA_STR;
        separator_str_length = SPIDER_SQL_COMMA_LEN;
        last_str = SPIDER_SQL_CLOSE_PAREN_STR;
        last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
      } else {
        func_name = SPIDER_SQL_IN_STR;
        func_name_length = SPIDER_SQL_IN_LEN;
        separator_str = SPIDER_SQL_COMMA_STR;
        separator_str_length = SPIDER_SQL_COMMA_LEN;
        last_str = SPIDER_SQL_CLOSE_PAREN_STR;
        last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
      }
      break;
    case Item_func::BETWEEN:
      if (((Item_func_opt_neg *) item_func)->negated)
      {
        func_name = SPIDER_SQL_NOT_BETWEEN_STR;
        func_name_length = SPIDER_SQL_NOT_BETWEEN_LEN;
        separator_str = SPIDER_SQL_AND_STR;
        separator_str_length = SPIDER_SQL_AND_LEN;
      } else {
        LEX_CSTRING org_func_name= item_func->func_name_cstring();
        func_name = org_func_name.str;
        func_name_length = org_func_name.length;
        separator_str = SPIDER_SQL_AND_STR;
        separator_str_length = SPIDER_SQL_AND_LEN;
      }
      break;
    case Item_func::FUNC_SP:
    case Item_func::UDF_FUNC:
      use_pushdown_udf = spider_param_use_pushdown_udf(
        spider->wide_handler->trx->thd,
        spider->share->use_pushdown_udf);
      if (!use_pushdown_udf)
        /*
          This is the default behavior because the remote nodes may deal with
          the function in an unexpected way (e.g. not having the same
          definition). Users can turn it on if they know what they are doing.
        */
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      {
        LEX_CSTRING org_func_name= item_func->func_name_cstring();
        func_name = org_func_name.str;
        func_name_length = org_func_name.length;
      }
      DBUG_PRINT("info",("spider func_name = %s", func_name));
      DBUG_PRINT("info",("spider func_name_length = %d", func_name_length));
      if (str->reserve(func_name_length + SPIDER_SQL_OPEN_PAREN_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(func_name, func_name_length);
      str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
      func_name = SPIDER_SQL_COMMA_STR;
      func_name_length = SPIDER_SQL_COMMA_LEN;
      separator_str = SPIDER_SQL_COMMA_STR;
      separator_str_length = SPIDER_SQL_COMMA_LEN;
      last_str = SPIDER_SQL_CLOSE_PAREN_STR;
      last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
      break;
    case Item_func::TRIG_COND_FUNC:
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    case Item_func::GUSERVAR_FUNC:
      str->length(str->length() - SPIDER_SQL_OPEN_PAREN_LEN);
      if (item_func->result_type() == STRING_RESULT)
        DBUG_RETURN(spider_db_open_item_string(item_func, NULL, spider, str,
          alias, alias_length, dbton_id, use_fields, fields));
      else
        DBUG_RETURN(spider_db_open_item_int(item_func, NULL, spider, str,
          alias, alias_length, dbton_id, use_fields, fields));
    case Item_func::FT_FUNC:
      if (spider_db_check_ft_idx(item_func, spider) == MAX_KEY)
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      start_item = 1;
      if (str->reserve(SPIDER_SQL_MATCH_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_MATCH_STR, SPIDER_SQL_MATCH_LEN);
      separator_str = SPIDER_SQL_COMMA_STR;
      separator_str_length = SPIDER_SQL_COMMA_LEN;
      last_str = SPIDER_SQL_CLOSE_PAREN_STR;
      last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
      break;
    case Item_func::SP_EQUALS_FUNC:
      func_name = SPIDER_SQL_MBR_EQUAL_STR;
      func_name_length = SPIDER_SQL_MBR_EQUAL_LEN;
      DBUG_PRINT("info",("spider func_name = %s", func_name));
      DBUG_PRINT("info",("spider func_name_length = %d", func_name_length));
      if (str->reserve(func_name_length))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(func_name, func_name_length);
      func_name = SPIDER_SQL_COMMA_STR;
      func_name_length = SPIDER_SQL_COMMA_LEN;
      separator_str = SPIDER_SQL_COMMA_STR;
      separator_str_length = SPIDER_SQL_COMMA_LEN;
      last_str = SPIDER_SQL_CLOSE_PAREN_STR;
      last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
      break;
    case Item_func::SP_DISJOINT_FUNC:
    case Item_func::SP_INTERSECTS_FUNC:
    case Item_func::SP_TOUCHES_FUNC:
    case Item_func::SP_CROSSES_FUNC:
    case Item_func::SP_WITHIN_FUNC:
    case Item_func::SP_CONTAINS_FUNC:
    case Item_func::SP_OVERLAPS_FUNC:
      {
        LEX_CSTRING org_func_name= item_func->func_name_cstring();
        func_name = org_func_name.str;
        func_name_length = org_func_name.length;
      }
      DBUG_PRINT("info",("spider func_name = %s", func_name));
      DBUG_PRINT("info",("spider func_name_length = %d", func_name_length));
      if (str->reserve(func_name_length + SPIDER_SQL_OPEN_PAREN_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(func_name, func_name_length);
      str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
      func_name = SPIDER_SQL_COMMA_STR;
      func_name_length = SPIDER_SQL_COMMA_LEN;
      separator_str = SPIDER_SQL_COMMA_STR;
      separator_str_length = SPIDER_SQL_COMMA_LEN;
      last_str = SPIDER_SQL_CLOSE_PAREN_STR;
      last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
      break;
    case Item_func::EQ_FUNC:
    case Item_func::EQUAL_FUNC:
    case Item_func::NE_FUNC:
    case Item_func::LT_FUNC:
    case Item_func::LE_FUNC:
    case Item_func::GE_FUNC:
    case Item_func::GT_FUNC:
    case Item_func::XOR_FUNC:
      func_name = (char*) item_func->func_name();
      func_name_length = strlen(func_name);
      break;
    case Item_func::LIKE_FUNC:
      if (((Item_func_like *)item_func)->get_negated())
      {
        func_name = SPIDER_SQL_NOT_LIKE_STR;
        func_name_length = SPIDER_SQL_NOT_LIKE_LEN;
      }
      else
      {
        LEX_CSTRING org_func_name= item_func->func_name_cstring();
        func_name = org_func_name.str;
        func_name_length = org_func_name.length;
      }
      break;
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    case Item_func::CASE_SEARCHED_FUNC:
    case Item_func::CASE_SIMPLE_FUNC:
      /*
        Arrangement of arguments:
        - Item_func_case_searched:
          when1 when2 ... whenk then1 then2 .. thenk [else]
        - Item_func_case_simple:
          value when1 when2 ... whenk then1 then2 .. thenk [else]
      */
      if (item_func->functype() == Item_func::CASE_SEARCHED_FUNC)
      {
        case_when_start= 0;
        case_when_count= item_count / 2;
        case_with_else= item_count % 2;
      }
      else
      {
        case_when_start= 1;
        case_when_count= (item_count - 1) / 2;
        case_with_else= item_count % 2 == 0;
      }
      if (str)
      {
        if (str->reserve(SPIDER_SQL_CASE_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_CASE_STR, SPIDER_SQL_CASE_LEN);
      }
      if (case_when_start > 0)
      {
        if ((error_num = spider_db_print_item_type(
          item_list[0], NULL, spider, str,
          alias, alias_length, dbton_id, use_fields, fields)))
          DBUG_RETURN(error_num);
      }
      for (i = 0; i < (uint) case_when_count; i++)
      {
        if (str)
        {
          if (str->reserve(SPIDER_SQL_WHEN_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_WHEN_STR, SPIDER_SQL_WHEN_LEN);
        }
        if ((error_num = spider_db_print_item_type(
          item_list[i + case_when_start], NULL, spider, str,
          alias, alias_length, dbton_id, use_fields, fields)))
          DBUG_RETURN(error_num);
        if (str)
        {
          if (str->reserve(SPIDER_SQL_THEN_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_THEN_STR, SPIDER_SQL_THEN_LEN);
        }
        if ((error_num = spider_db_print_item_type(
          item_list[i + case_when_start + case_when_count], NULL, spider, str,
          alias, alias_length, dbton_id, use_fields, fields)))
          DBUG_RETURN(error_num);
      }
      if (case_with_else)
      {
        if (str)
        {
          if (str->reserve(SPIDER_SQL_ELSE_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_ELSE_STR, SPIDER_SQL_ELSE_LEN);
        }
        if ((error_num = spider_db_print_item_type(
          item_list[item_count - 1], NULL, spider, str,
          alias, alias_length, dbton_id, use_fields, fields)))
          DBUG_RETURN(error_num);
      }
      if (str)
      {
        if (str->reserve(SPIDER_SQL_END_LEN + SPIDER_SQL_CLOSE_PAREN_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_END_STR, SPIDER_SQL_END_LEN);
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,
          SPIDER_SQL_CLOSE_PAREN_LEN);
      }
      DBUG_RETURN(0);
    case Item_func::JSON_EXTRACT_FUNC:
      func_name = (char*) item_func->func_name();
      func_name_length = strlen(func_name);
      if (str->reserve(func_name_length + SPIDER_SQL_OPEN_PAREN_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(func_name, func_name_length);
      str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
      func_name = SPIDER_SQL_COMMA_STR;
      func_name_length = SPIDER_SQL_COMMA_LEN;
      separator_str = SPIDER_SQL_COMMA_STR;
      separator_str_length = SPIDER_SQL_COMMA_LEN;
      last_str = SPIDER_SQL_CLOSE_PAREN_STR;
      last_str_length = SPIDER_SQL_CLOSE_PAREN_LEN;
      break;
    case Item_func::MULT_EQUAL_FUNC:
      /* If there is still Item_equal by the time of
      JOIN::make_aggr_tables_info() where the spider group by handler
      is created, it indicates a bug in the optimizer, because there
      shouldn't be any. */
      push_warning_printf(
        spider->wide_handler->trx->thd,
        SPIDER_WARN_LEVEL_WARN, ER_INTERNAL_ERROR,
        ER_THD(spider->wide_handler->trx->thd, ER_INTERNAL_ERROR),
        "Spider group by handler: Encountered multiple equalities, likely "
        "an optimizer bug");
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    default:
      THD *thd = spider->wide_handler->trx->thd;
      SPIDER_SHARE *share = spider->share;
      if (spider_param_skip_default_condition(thd,
        share->skip_default_condition))
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      LEX_CSTRING org_func_name= item_func->func_name_cstring();
      func_name = org_func_name.str;
      func_name_length = org_func_name.length;
      break;
  }
  DBUG_PRINT("info",("spider func_name = %s", func_name));
  DBUG_PRINT("info",("spider func_name_length = %d", func_name_length));
  DBUG_PRINT("info",("spider separator_str = %s", separator_str));
  DBUG_PRINT("info",("spider separator_str_length = %d", separator_str_length));
  DBUG_PRINT("info",("spider last_str = %s", last_str));
  DBUG_PRINT("info",("spider last_str_length = %d", last_str_length));
  if (item_count)
  {
    /* Find the field in the list of items of the expression tree */
    field = spider_db_find_field_in_item_list(item_list,
                                              item_count, start_item,
                                              str,
                                              func_name, func_name_length);
    item_count--;
    /*
      Loop through the items of the current function expression to
      print its portion of the statement
    */
    for (i = start_item; i < item_count; i++)
    {
      item = item_list[i];
      if ((error_num = spider_db_print_item_type(item, field, spider, str,
        alias, alias_length, dbton_id, use_fields, fields)))
        DBUG_RETURN(error_num);
      if (i == 1)
      {
        /* Remaining operands need to be preceded by the separator */
        func_name = separator_str;
        func_name_length = separator_str_length;
      }
      if (str->reserve(func_name_length + SPIDER_SQL_SPACE_LEN * 2))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
      str->q_append(func_name, func_name_length);
      str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
    }

    /* Print the last operand value */
    item = item_list[i];
    if ((error_num = spider_db_print_item_type(item, field, spider, str,
      alias, alias_length, dbton_id, use_fields, fields)))
      DBUG_RETURN(error_num);
  }

  if (item_func->functype() == Item_func::FT_FUNC)
  {
    Item_func_match *item_func_match = (Item_func_match *)item_func;
    if (str->reserve(SPIDER_SQL_AGAINST_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_AGAINST_STR, SPIDER_SQL_AGAINST_LEN);
    item = item_list[0];
    if ((error_num = spider_db_print_item_type(item, NULL, spider, str,
      alias, alias_length, dbton_id, use_fields, fields)))
      DBUG_RETURN(error_num);
    if (str->reserve(
      ((item_func_match->match_flags & FT_BOOL) ?
        SPIDER_SQL_IN_BOOLEAN_MODE_LEN : 0) +
      ((item_func_match->match_flags & FT_EXPAND) ?
        SPIDER_SQL_WITH_QUERY_EXPANSION_LEN : 0)
    ))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    if (item_func_match->match_flags & FT_BOOL)
      str->q_append(SPIDER_SQL_IN_BOOLEAN_MODE_STR,
        SPIDER_SQL_IN_BOOLEAN_MODE_LEN);
    if (item_func_match->match_flags & FT_EXPAND)
      str->q_append(SPIDER_SQL_WITH_QUERY_EXPANSION_STR,
        SPIDER_SQL_WITH_QUERY_EXPANSION_LEN);
  } else if (item_func->functype() == Item_func::UNKNOWN_FUNC)
  {
    if (
      func_name_length == 7 &&
      !strncasecmp("convert", func_name, func_name_length)
    ) {
      Item_func_conv_charset *item_func_conv_charset =
        (Item_func_conv_charset *)item_func;
      CHARSET_INFO *conv_charset =
        item_func_conv_charset->SPIDER_Item_func_conv_charset_conv_charset;
      uint cset_length = conv_charset->cs_name.length;
      if (str->reserve(SPIDER_SQL_USING_LEN + cset_length))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_USING_STR, SPIDER_SQL_USING_LEN);
      str->q_append(conv_charset->cs_name.str, cset_length);
    }
  }
  if (merge_func)
    str->length(str->length() - SPIDER_SQL_CLOSE_PAREN_LEN);
  if (str->reserve(last_str_length + SPIDER_SQL_CLOSE_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(last_str, last_str_length);
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::open_item_sum_func(
  Item_sum *item_sum,
  ha_spider *spider,
  spider_string *str,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields
) {
  uint roop_count, item_count = item_sum->get_arg_count();
  int error_num;
  DBUG_ENTER("spider_db_mbase_util::open_item_sum_func");
  DBUG_PRINT("info",("spider Sumfunctype = %d", item_sum->sum_func()));
  switch (item_sum->sum_func())
  {
    case Item_sum::COUNT_FUNC:
    case Item_sum::SUM_FUNC:
    case Item_sum::MIN_FUNC:
    case Item_sum::MAX_FUNC:
      {
        LEX_CSTRING org_func_name= item_sum->func_name_cstring();
        const char *func_name = org_func_name.str;
        uint func_name_length = org_func_name.length;
        Item *item, **args = item_sum->get_args();
        if (str)
        {
          if (str->reserve(func_name_length))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(func_name, func_name_length);
        }
        if (item_count)
        {
          item_count--;
          for (roop_count = 0; roop_count < item_count; roop_count++)
          {
            item = args[roop_count];
            if ((error_num = spider_db_print_item_type(item, NULL, spider, str,
              alias, alias_length, dbton_id, use_fields, fields)))
              DBUG_RETURN(error_num);
            if (str)
            {
              if (str->reserve(SPIDER_SQL_COMMA_LEN))
                DBUG_RETURN(HA_ERR_OUT_OF_MEM);
              str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
            }
          }
          item = args[roop_count];
          if ((error_num = spider_db_print_item_type(item, NULL, spider, str,
            alias, alias_length, dbton_id, use_fields, fields)))
            DBUG_RETURN(error_num);
        }
        if (str)
        {
          if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,
            SPIDER_SQL_CLOSE_PAREN_LEN);
        }
      }
      break;
    case Item_sum::COUNT_DISTINCT_FUNC:
    case Item_sum::SUM_DISTINCT_FUNC:
    case Item_sum::AVG_FUNC:
    case Item_sum::AVG_DISTINCT_FUNC:
      {
        if (!use_fields)
          DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
        LEX_CSTRING org_func_name= item_sum->func_name_cstring();
        const char *func_name = org_func_name.str;
        uint func_name_length = org_func_name.length;
        Item *item, **args = item_sum->get_args();
        if (str)
        {
          if (str->reserve(func_name_length))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(func_name, func_name_length);
        }
        if (item_count)
        {
          item_count--;
          for (roop_count = 0; roop_count < item_count; roop_count++)
          {
            item = args[roop_count];
            if ((error_num = spider_db_print_item_type(item, NULL, spider, str,
              alias, alias_length, dbton_id, use_fields, fields)))
              DBUG_RETURN(error_num);
            if (str)
            {
              if (str->reserve(SPIDER_SQL_COMMA_LEN))
                DBUG_RETURN(HA_ERR_OUT_OF_MEM);
              str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
            }
          }
          item = args[roop_count];
          if ((error_num = spider_db_print_item_type(item, NULL, spider, str,
            alias, alias_length, dbton_id, use_fields, fields)))
            DBUG_RETURN(error_num);
        }
        if (str)
        {
          if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,
            SPIDER_SQL_CLOSE_PAREN_LEN);
        }
      }
      break;
    case Item_sum::STD_FUNC:
    case Item_sum::VARIANCE_FUNC:
    case Item_sum::SUM_BIT_FUNC:
    case Item_sum::UDF_SUM_FUNC:
    case Item_sum::GROUP_CONCAT_FUNC:
    default:
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
  }
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_escaped_util(
  spider_string *to,
  String *from
) {
  DBUG_ENTER("spider_db_mbase_util::append_escaped_util");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider from=%s", from->charset()->cs_name.str));
  DBUG_PRINT("info",("spider to=%s", to->charset()->cs_name.str));
  to->append_escape_string(from->ptr(), from->length());
  DBUG_RETURN(0);
}

/*
  Walk a TABLE_LIST, or format it to a string and append it.

  If str is NULL, walk the nested join (if any) to determine whether
  to create a group by handler. Otherwise, format the TABLE_LIST to a
  string and append it to str.

  Adapted from TABLE_LIST::print().
*/
int spider_db_mbase_util::append_table_list(spider_fields *fields,
                                            spider_string *str,
                                            TABLE_LIST *table,
                                            table_map *upper_usable_tables,
                                            table_map eliminated_tables)
{
  DBUG_ENTER("spider_db_mbase_util::append_table_list");
  /* Eliminated tables were removed from append_join(). */
  DBUG_ASSERT(!is_eliminated_table(eliminated_tables, table));
  if (!str)                     /* First pass (GBH creation) */
  {
    DBUG_ASSERT(upper_usable_tables);
    if (table->nested_join)
      DBUG_RETURN(append_join(fields, str,
                              &table->nested_join->join_list,
                              upper_usable_tables, eliminated_tables));
    /* jtbm is a kind of semi join, and TABLE_LIST::print() adds an
    extra " <materialize> " annotation. */
    if (table->jtbm_subselect)
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    /* TODO: These conditions are printed in a different way in
    TABLE_LIST::print(), but they do not seem to occur very often.
    Let's not worry about them now. */
    if (table->view_name.str || table->derived || table->table_function)
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    *upper_usable_tables |= table->table->map;
    DBUG_RETURN(0);
  }
  /* Second pass (query execution) */
  DBUG_ASSERT(!upper_usable_tables);
  if (table->nested_join)
  {
    if (str->append("("))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    if (int error_num= append_join(
          fields, str, &table->nested_join->join_list,
          upper_usable_tables, eliminated_tables))
      DBUG_RETURN(error_num);
    if (str->append(")"))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    DBUG_RETURN(0);
  }
  /* These have been ruled out during the creation of the group by
  handler, see above. */
  DBUG_ASSERT(!table->jtbm_subselect);
  DBUG_ASSERT(!table->view_name.str);
  DBUG_ASSERT(!table->derived);
  DBUG_ASSERT(!table->table_function);
  /* We have a "normal" table. Print it and append to str. */
  SPIDER_TABLE_HOLDER *table_holder = fields->get_table_holder(table->table);
  ha_spider *spd = table_holder->spider;
  spider_mbase_share *db_share =
    (spider_mbase_share *) spd->share->dbton_share[dbton_id];
  spider_mbase_handler *dbton_hdl =
    (spider_mbase_handler *) spd->dbton_handler[dbton_id];
  if (table->table->const_table)
  {
    if (str->append(STRING_WITH_LEN("(select 1)")))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  else
    if (int error_num= db_share->append_table_name(
          str, spd->conn_link_idx[dbton_hdl->first_link_idx]))
      DBUG_RETURN(error_num);
  if (str->append(" ") ||
      str->append(table_holder->alias->ptr(),
                  /* Don't append the trailing dot */
                  table_holder->alias->length() - 1))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  DBUG_RETURN(0);
}

/*
  Walk an array of TABLE_LIST's, or format it to a string and append it.

  If str is NULL, walk each TABLE_LIST to determine whether to create
  a group by handler. Otherwise, format the TABLE_LISTs to a string
  and append it to str.

  Adapted from print_table_array().
*/
int spider_db_mbase_util::append_table_array(spider_fields *fields,
                                             spider_string *str,
                                             TABLE_LIST **table,
                                             TABLE_LIST **end,
                                             table_map *upper_usable_tables,
                                             table_map eliminated_tables)
{
  DBUG_ENTER("spider_db_mbase_util::append_table_array");
  if (str)
  {
    DBUG_ASSERT(!upper_usable_tables);
    if (int error_num= append_table_list(fields, str, *table, NULL,
                                         eliminated_tables))
      DBUG_RETURN(error_num);

    for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++)
    {
      TABLE_LIST *curr= *tbl;

      /* JOIN_TYPE_OUTER is just a marker unrelated to real join */
      if (curr->outer_join & (JOIN_TYPE_LEFT|JOIN_TYPE_RIGHT))
      {
        /* MySQL converts right to left joins */
        if (str->append(STRING_WITH_LEN(" left join ")))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      else if (curr->straight)
      {
        if (str->append(STRING_WITH_LEN(" straight_join ")))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      /* semi join should already have been ruled out during the
      creation of the group by handler. */
      else if (curr->sj_inner_tables)
        DBUG_ASSERT(0);
      else
        if (str->append(STRING_WITH_LEN(" join ")))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);

      if (int error_num= append_table_list(fields, str, curr, NULL,
                                           eliminated_tables))
        DBUG_RETURN(error_num);

      if (curr->on_expr)
      {
        if (str->append(STRING_WITH_LEN(" on ")))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        if (int error_num=
            spider_db_print_item_type(curr->on_expr, NULL,
                                      fields->get_first_table_holder()->spider,
                                      str, NULL, 0, dbton_id, TRUE, fields))
          DBUG_RETURN(error_num);
      }
    }
  }
  else                        /* str == NULL */
  {
    table_map usable_tables= 0;
    if (int error_num= append_table_list(fields, str, *table,
                                         &usable_tables, eliminated_tables))
      DBUG_RETURN(error_num);
    for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++)
    {
      TABLE_LIST *curr= *tbl;
      /* semi join is an "internal" join and is unsupported. */
      if (curr->sj_inner_tables)
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      if (int error_num= append_table_list(fields, str, curr,
                                           &usable_tables, eliminated_tables))
        DBUG_RETURN(error_num);
      if (curr->on_expr)
      {
        /* The join refers to fields outside of the current context,
        and cannot be handled by a group by handler. */
        if ((curr->on_expr->used_tables() & usable_tables) !=
            curr->on_expr->used_tables())
          DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
        if (int error_num=
            spider_db_print_item_type(curr->on_expr, NULL,
                                      fields->get_first_table_holder()->spider,
                                      str, NULL, 0, dbton_id, TRUE, fields))
          DBUG_RETURN(error_num);
      }
    }
    /* Update usable tables in the outer context. */
    if (upper_usable_tables)
      *upper_usable_tables |= usable_tables;
  }
  DBUG_RETURN(0);
}

/*
  Walk a join, or format it to a string and append the string.

  Skip all eliminated tables.

  If str is NULL, walk the tables to determine whether to create a
  group by handler. Otherwise, format the join to a string and append
  it to str.

  Adapted from print_join().
*/
int spider_db_mbase_util::append_join(spider_fields *fields,
                                      spider_string *str,
                                      List<TABLE_LIST> *tables,
                                      table_map *upper_usable_tables,
                                      table_map eliminated_tables)
{
  /* List is reversed => we should reverse it before using */
  List_iterator_fast<TABLE_LIST> ti(*tables);
  TABLE_LIST **table;
  THD *thd= fields->get_first_table_holder()->spider->wide_handler->trx->thd;
  DBUG_ENTER("spider_db_mbase_util::append_join");

  size_t tables_to_print= 0;

  for (TABLE_LIST *t= ti++; t ; t= ti++)
  {
    /* optimized_away implies const_table */
    DBUG_ASSERT(!t->optimized_away || t->table->const_table);
    if (!is_eliminated_table(eliminated_tables, t))
      tables_to_print++;
  }
  if (tables_to_print == 0)
  {
    if (str && str->append(STRING_WITH_LEN("dual")))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    DBUG_RETURN(0);
  }
  ti.rewind();

  if (!(table= thd->alloc<TABLE_LIST *>(tables_to_print)))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);

  TABLE_LIST *tmp, **t= table + (tables_to_print - 1);
  while ((tmp= ti++))
    if (!is_eliminated_table(eliminated_tables, tmp))
      *t--= tmp;

  DBUG_ASSERT(tables->elements >= 1);
  if ((*table)->sj_inner_tables)
  {
    /* Semi join is not supported. */
    if (!str)
      DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
    /* Semi join should have been skipped in the first pass. */
    else
      DBUG_ASSERT(0);
  }
  int error_num= append_table_array(
    fields, str, table, table + tables_to_print, upper_usable_tables,
    eliminated_tables);
  DBUG_RETURN(error_num);
}

int spider_db_mbase_util::append_from_and_tables(
  ha_spider *spider,
  spider_fields *fields,
  spider_string *str,
  TABLE_LIST *table_list,
  uint table_count
)
{
  DBUG_ENTER("spider_db_mbase_util::append_from_and_tables");
  if (str && str->append(" from "))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  const table_map eliminated_tables= table_list->select_lex->join ?
    table_list->select_lex->join->eliminated_tables : 0;
  int error_num = append_join(fields, str, table_list->select_lex->join_list,
                              NULL, eliminated_tables);
  DBUG_RETURN(error_num);
}
int spider_db_mbase_util::append_where(
  spider_string *str
) {
  DBUG_ENTER("spider_db_mbase_util::append_where");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_WHERE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_WHERE_STR, SPIDER_SQL_WHERE_LEN);
  DBUG_RETURN(0);
}

int spider_db_mbase_util::append_having(
  spider_string *str
) {
  DBUG_ENTER("spider_db_mbase_util::append_having");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_HAVING_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_HAVING_STR, SPIDER_SQL_HAVING_LEN);
  DBUG_RETURN(0);
}

bool spider_db_mbase_util::tables_on_different_db_are_joinable()
{
  DBUG_ENTER("spider_db_mbase_util::tables_on_different_db_are_joinable");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

bool spider_db_mbase_util::socket_has_default_value()
{
  DBUG_ENTER("spider_db_mbase_util::socket_has_default_value");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

bool spider_db_mbase_util::database_has_default_value()
{
  DBUG_ENTER("spider_db_mbase_util::database_has_default_value");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

bool spider_db_mbase_util::default_file_has_default_value()
{
  DBUG_ENTER("spider_db_mbase_util::default_file_has_default_value");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

bool spider_db_mbase_util::host_has_default_value()
{
  DBUG_ENTER("spider_db_mbase_util::host_has_default_value");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

bool spider_db_mbase_util::port_has_default_value()
{
  DBUG_ENTER("spider_db_mbase_util::port_has_default_value");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

bool spider_db_mbase_util::append_charset_name_before_string()
{
  DBUG_ENTER("spider_db_mbase_util::append_charset_name_before_string");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

spider_mbase_share::spider_mbase_share(
  st_spider_share *share,
  uint dbton_id,
  spider_db_mbase_util *spider_db_mbase_utility
) : spider_db_share(
  share,
  dbton_id
),
  spider_db_mbase_utility(spider_db_mbase_utility),
  table_select(NULL),
  table_select_pos(0),
  key_select(NULL),
  key_select_pos(NULL),
  key_hint(NULL),
  show_table_status(NULL),
  show_records(NULL),
  show_index(NULL),
  table_names_str(NULL),
  db_names_str(NULL),
  db_table_str(NULL),
  db_table_str_hash_value(NULL),
  table_nm_max_length(0),
  db_nm_max_length(0),
  column_name_str(NULL),
  same_db_table_name(TRUE),
  first_all_link_idx(-1)
{
  DBUG_ENTER("spider_mbase_share::spider_mbase_share");
  DBUG_PRINT("info",("spider this=%p", this));
  spider_alloc_calc_mem_init(mem_calc, SPD_MID_MBASE_SHARE_SPIDER_MBASE_SHARE_1);
  spider_alloc_calc_mem(spider_current_trx, mem_calc, sizeof(*this));
  DBUG_VOID_RETURN;
}

spider_mysql_share::spider_mysql_share(
  st_spider_share *share
) : spider_mbase_share(
  share,
  spider_db_mysql_utility.dbton_id,
  &spider_db_mysql_utility
) {
  DBUG_ENTER("spider_mysql_share::spider_mysql_share");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}
spider_mariadb_share::spider_mariadb_share(
  st_spider_share *share
) : spider_mbase_share(
  share,
  spider_db_mariadb_utility.dbton_id,
  &spider_db_mariadb_utility
) {
  DBUG_ENTER("spider_mariadb_share::spider_mariadb_share");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mbase_share::~spider_mbase_share()
{
  DBUG_ENTER("spider_mbase_share::~spider_mbase_share");
  DBUG_PRINT("info",("spider this=%p", this));
  if (table_select)
    delete [] table_select;
  if (key_select)
    delete [] key_select;
  if (key_hint)
    delete [] key_hint;
  free_show_table_status();
  free_show_records();
  free_show_index();
  free_column_name_str();
  free_table_names_str();
  if (key_select_pos)
  {
    spider_free(spider_current_trx, key_select_pos, MYF(0));
  }
  spider_free_mem_calc(spider_current_trx, mem_calc_id, sizeof(*this));
  DBUG_VOID_RETURN;
}

spider_mysql_share::~spider_mysql_share()
{
  DBUG_ENTER("spider_mysql_share::~spider_mysql_share");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mariadb_share::~spider_mariadb_share()
{
  DBUG_ENTER("spider_mariadb_share::~spider_mariadb_share");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

int spider_mbase_share::init()
{
  int error_num;
  uint roop_count;
  TABLE_SHARE *table_share = spider_share->table_share;
  uint keys = table_share ? table_share->keys : 0;
  DBUG_ENTER("spider_mbase_share::init");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!(key_select_pos = (int *)
    spider_bulk_alloc_mem(spider_current_trx, SPD_MID_MBASE_SHARE_INIT_1,
      __func__, __FILE__, __LINE__, MYF(MY_WME | MY_ZEROFILL),
      &key_select_pos,
        sizeof(int) * keys,
      &db_table_str_hash_value,
        sizeof(my_hash_value_type) * spider_share->all_link_count,
      NullS))
  ) {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }

  if (keys > 0)
    if (!(key_hint = new spider_string[keys]))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  for (roop_count = 0; roop_count < keys; roop_count++)
  {
    key_hint[roop_count].init_calc_mem(SPD_MID_MBASE_SHARE_INIT_2);
    key_hint[roop_count].set_charset(spider_share->access_charset);
  }
  DBUG_PRINT("info",("spider key_hint=%p", key_hint));

  if (!(table_select = new spider_string[1]))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  if (keys > 0)
    if (!(key_select = new spider_string[keys]))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  if ((error_num = create_table_names_str()) ||
    (table_share &&
      (
        (error_num = create_column_name_str()) ||
        (error_num = convert_key_hint_str()) ||
        (error_num = append_show_table_status()) ||
        (error_num = append_show_records()) ||
        (error_num = append_show_index())
      )
    )
  ) {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }

  table_select->init_calc_mem(SPD_MID_MBASE_SHARE_INIT_3);
  if (table_share && (error_num = append_table_select()))
    DBUG_RETURN(error_num);

  for (roop_count = 0; roop_count < keys; roop_count++)
  {
    key_select[roop_count].init_calc_mem(SPD_MID_MBASE_SHARE_INIT_4);
    if ((error_num = append_key_select(roop_count)))
      DBUG_RETURN(error_num);
  }

  DBUG_RETURN(error_num);
}

uint spider_mbase_share::get_column_name_length(
  uint field_index
) {
  DBUG_ENTER("spider_mbase_share::get_column_name_length");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(column_name_str[field_index].length());
}

int spider_mbase_share::append_column_name(
  spider_string *str,
  uint field_index
) {
  int error_num;
  DBUG_ENTER("spider_mbase_share::append_column_name");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = spider_db_mbase_utility->append_name(str,
    column_name_str[field_index].ptr(), column_name_str[field_index].length());
  DBUG_RETURN(error_num);
}

int spider_mbase_share::append_column_name_with_alias(
  spider_string *str,
  uint field_index,
  const char *alias,
  uint alias_length
) {
  DBUG_ENTER("spider_mbase_share::append_column_name_with_alias");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(
    alias_length +
    column_name_str[field_index].length() +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 2))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(alias, alias_length);
  append_column_name(str, field_index);
  DBUG_RETURN(0);
}

int spider_mbase_share::append_table_name(
  spider_string *str,
  int all_link_idx
) {
  const char *db_nm = db_names_str[all_link_idx].ptr();
  uint db_nm_len = db_names_str[all_link_idx].length();
  const char *table_nm = table_names_str[all_link_idx].ptr();
  uint table_nm_len = table_names_str[all_link_idx].length();
  DBUG_ENTER("spider_mbase_share::append_table_name");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(db_nm_len + SPIDER_SQL_DOT_LEN + table_nm_len +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  spider_db_mbase_utility->append_name(str, db_nm, db_nm_len);
  str->q_append(SPIDER_SQL_DOT_STR, SPIDER_SQL_DOT_LEN);
  spider_db_mbase_utility->append_name(str, table_nm, table_nm_len);
  DBUG_RETURN(0);
}

int spider_mbase_share::append_table_name_with_adjusting(
  spider_string *str,
  int all_link_idx
) {
  const char *db_nm = db_names_str[all_link_idx].ptr();
  uint db_nm_len = db_names_str[all_link_idx].length();
  uint db_nm_max_len = db_nm_max_length;
  const char *table_nm = table_names_str[all_link_idx].ptr();
  uint table_nm_len = table_names_str[all_link_idx].length();
  uint table_nm_max_len = table_nm_max_length;
  DBUG_ENTER("spider_mbase_share::append_table_name_with_adjusting");
  DBUG_PRINT("info",("spider this=%p", this));
  spider_db_mbase_utility->append_name(str, db_nm, db_nm_len);
  str->q_append(SPIDER_SQL_DOT_STR, SPIDER_SQL_DOT_LEN);
  spider_db_mbase_utility->append_name(str, table_nm, table_nm_len);
  uint length =
    db_nm_max_len - db_nm_len +
    table_nm_max_len - table_nm_len;
  memset((char *) str->ptr() + str->length(), ' ', length);
  str->length(str->length() + length);
  DBUG_RETURN(0);
}

int spider_mbase_share::append_from_with_adjusted_table_name(
  spider_string *str,
  int *table_name_pos
) {
  const char *db_nm = db_names_str[0].ptr();
  uint db_nm_len = db_names_str[0].length();
  uint db_nm_max_len = db_nm_max_length;
  const char *table_nm = table_names_str[0].ptr();
  uint table_nm_len = table_names_str[0].length();
  uint table_nm_max_len = table_nm_max_length;
  DBUG_ENTER("spider_mbase_share::append_from_with_adjusted_table_name");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_FROM_LEN + db_nm_max_length +
    SPIDER_SQL_DOT_LEN + table_nm_max_length +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_FROM_STR, SPIDER_SQL_FROM_LEN);
  *table_name_pos = str->length();
  spider_db_mbase_utility->append_name(str, db_nm, db_nm_len);
  str->q_append(SPIDER_SQL_DOT_STR, SPIDER_SQL_DOT_LEN);
  spider_db_mbase_utility->append_name(str, table_nm, table_nm_len);
  uint length =
    db_nm_max_len - db_nm_len +
    table_nm_max_len - table_nm_len;
  memset((char *) str->ptr() + str->length(), ' ', length);
  str->length(str->length() + length);
  DBUG_RETURN(0);
}

int spider_mbase_share::create_table_names_str()
{
  int error_num, roop_count;
  uint table_nm_len, db_nm_len;
  spider_string *str, *first_tbl_nm_str, *first_db_nm_str, *first_db_tbl_str;
  char *first_tbl_nm, *first_db_nm;
  DBUG_ENTER("spider_mbase_share::create_table_names_str");
  table_names_str = NULL;
  db_names_str = NULL;
  db_table_str = NULL;
  if (!(table_names_str = new spider_string[spider_share->all_link_count]))
  {
    error_num = HA_ERR_OUT_OF_MEM;
    goto error;
  }
  if (!(db_names_str = new spider_string[spider_share->all_link_count]))
  {
    error_num = HA_ERR_OUT_OF_MEM;
    goto error;
  }
  if (!(db_table_str = new spider_string[spider_share->all_link_count]))
  {
    error_num = HA_ERR_OUT_OF_MEM;
    goto error;
  }

  same_db_table_name = TRUE;
  first_tbl_nm = spider_share->tgt_table_names[0];
  first_db_nm = spider_share->tgt_dbs[0];
  table_nm_len = spider_share->tgt_table_names_lengths[0];
  db_nm_len = spider_share->tgt_dbs_lengths[0];
  first_tbl_nm_str = &table_names_str[0];
  first_db_nm_str = &db_names_str[0];
  first_db_tbl_str = &db_table_str[0];
  for (roop_count = 0; roop_count < (int) spider_share->all_link_count;
    roop_count++)
  {
    table_names_str[roop_count].init_calc_mem(SPD_MID_MBASE_SHARE_CREATE_TABLE_NAMES_STR_1);
    db_names_str[roop_count].init_calc_mem(SPD_MID_MBASE_SHARE_CREATE_TABLE_NAMES_STR_2);
    db_table_str[roop_count].init_calc_mem(SPD_MID_MBASE_SHARE_CREATE_TABLE_NAMES_STR_3);
    if (spider_share->sql_dbton_ids[roop_count] != dbton_id)
      continue;
    if (first_all_link_idx == -1)
      first_all_link_idx = roop_count;

    str = &table_names_str[roop_count];
    if (
      roop_count != 0 &&
      same_db_table_name &&
      spider_share->tgt_table_names_lengths[roop_count] == table_nm_len &&
      !memcmp(first_tbl_nm, spider_share->tgt_table_names[roop_count],
        table_nm_len)
    ) {
      if (str->copy(*first_tbl_nm_str))
      {
        error_num = HA_ERR_OUT_OF_MEM;
        goto error;
      }
    } else {
      str->set_charset(spider_share->access_charset);
      if ((error_num = spider_db_append_name_with_quote_str(str,
        spider_share->tgt_table_names[roop_count], dbton_id)))
        goto error;
      if (roop_count)
      {
        same_db_table_name = FALSE;
        DBUG_PRINT("info", ("spider found different table name %s",
          spider_share->tgt_table_names[roop_count]));
        if (str->length() > table_nm_max_length)
          table_nm_max_length = str->length();
      } else
        table_nm_max_length = str->length();
    }

    str = &db_names_str[roop_count];
    if (
      roop_count != 0 &&
      same_db_table_name &&
      spider_share->tgt_dbs_lengths[roop_count] == db_nm_len &&
      !memcmp(first_db_nm, spider_share->tgt_dbs[roop_count],
        db_nm_len)
    ) {
      if (str->copy(*first_db_nm_str))
      {
        error_num = HA_ERR_OUT_OF_MEM;
        goto error;
      }
    } else {
      str->set_charset(spider_share->access_charset);
      if ((error_num = spider_db_append_name_with_quote_str(str,
        spider_share->tgt_dbs[roop_count], dbton_id)))
        goto error;
      if (roop_count)
      {
        same_db_table_name = FALSE;
        DBUG_PRINT("info", ("spider found different db name %s",
          spider_share->tgt_dbs[roop_count]));
        if (str->length() > db_nm_max_length)
          db_nm_max_length = str->length();
      } else
        db_nm_max_length = str->length();
    }

    str = &db_table_str[roop_count];
    if (
      roop_count != 0 &&
      same_db_table_name
    ) {
      if (str->copy(*first_db_tbl_str))
      {
        error_num = HA_ERR_OUT_OF_MEM;
        goto error;
      }
    } else {
      str->set_charset(spider_share->access_charset);
      if ((error_num = append_table_name(str, roop_count)))
        goto error;
    }
    db_table_str_hash_value[roop_count] = my_calc_hash(
      &spider_open_connections, (uchar*) str->ptr(), str->length());
  }
  DBUG_RETURN(0);

error:
  if (db_table_str)
  {
    delete [] db_table_str;
    db_table_str = NULL;
  }
  if (db_names_str)
  {
    delete [] db_names_str;
    db_names_str = NULL;
  }
  if (table_names_str)
  {
    delete [] table_names_str;
    table_names_str = NULL;
  }
  DBUG_RETURN(error_num);
}

void spider_mbase_share::free_table_names_str()
{
  DBUG_ENTER("spider_mbase_share::free_table_names_str");
  if (db_table_str)
  {
    delete [] db_table_str;
    db_table_str = NULL;
  }
  if (db_names_str)
  {
    delete [] db_names_str;
    db_names_str = NULL;
  }
  if (table_names_str)
  {
    delete [] table_names_str;
    table_names_str = NULL;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_share::create_column_name_str()
{
  spider_string *str;
  int error_num;
  Field **field;
  TABLE_SHARE *table_share = spider_share->table_share;
  DBUG_ENTER("spider_mbase_share::create_column_name_str");
  if (table_share->fields)
    if (!(column_name_str = new spider_string[table_share->fields]))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  for (field = table_share->field, str = column_name_str;
   *field; field++, str++)
  {
    str->init_calc_mem(SPD_MID_MBASE_SHARE_CREATE_COLUMN_NAME_STR_1);
    str->set_charset(spider_share->access_charset);
    if ((error_num = spider_db_append_name_with_quote_str(str,
      (*field)->field_name, dbton_id)))
      goto error;
  }
  DBUG_RETURN(0);

error:
  if (column_name_str)
  {
    delete [] column_name_str;
    column_name_str = NULL;
  }
  DBUG_RETURN(error_num);
}

void spider_mbase_share::free_column_name_str()
{
  DBUG_ENTER("spider_mbase_share::free_column_name_str");
  if (column_name_str)
  {
    delete [] column_name_str;
    column_name_str = NULL;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_share::convert_key_hint_str()
{
  spider_string *tmp_key_hint;
  int roop_count;
  TABLE_SHARE *table_share = spider_share->table_share;
  DBUG_ENTER("spider_mbase_share::convert_key_hint_str");
  if (spider_share->access_charset->cset != system_charset_info->cset)
  {
    /* need conversion */
    for (roop_count = 0, tmp_key_hint = key_hint;
      roop_count < (int) table_share->keys; roop_count++, tmp_key_hint++)
    {
      tmp_key_hint->length(0);
      if (tmp_key_hint->append(spider_share->key_hint[roop_count].ptr(),
        spider_share->key_hint[roop_count].length(), system_charset_info))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
  } else {
    for (roop_count = 0, tmp_key_hint = key_hint;
      roop_count < (int) table_share->keys; roop_count++, tmp_key_hint++)
    {
      if (tmp_key_hint->copy(spider_share->key_hint[roop_count]))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
  }
  DBUG_RETURN(0);
}

int spider_mbase_share::append_show_table_status()
{
  int roop_count;
  spider_string *str;
  DBUG_ENTER("spider_mysql_append_show_table_status");
  if (!(show_table_status =
    new spider_string[2 * spider_share->all_link_count]))
    goto error;

  for (roop_count = 0; roop_count < (int) spider_share->all_link_count;
    roop_count++)
  {
    show_table_status[0 + (2 * roop_count)].init_calc_mem(SPD_MID_MBASE_SHARE_APPEND_SHOW_TABLE_STATUS_1);
    show_table_status[1 + (2 * roop_count)].init_calc_mem(SPD_MID_MBASE_SHARE_APPEND_SHOW_TABLE_STATUS_2);
    if (spider_share->sql_dbton_ids[roop_count] != dbton_id)
      continue;

    if (
      show_table_status[0 + (2 * roop_count)].reserve(
        SPIDER_SQL_SHOW_TABLE_STATUS_LEN +
        db_names_str[roop_count].length() +
        SPIDER_SQL_LIKE_LEN + table_names_str[roop_count].length() +
        ((SPIDER_SQL_NAME_QUOTE_LEN) * 2) +
        ((SPIDER_SQL_VALUE_QUOTE_LEN) * 2)) ||
      show_table_status[1 + (2 * roop_count)].reserve(
        SPIDER_SQL_SELECT_TABLES_STATUS_LEN +
        db_names_str[roop_count].length() +
        SPIDER_SQL_AND_LEN + SPIDER_SQL_TABLE_NAME_LEN + SPIDER_SQL_EQUAL_LEN +
        table_names_str[roop_count].length() +
        ((SPIDER_SQL_VALUE_QUOTE_LEN) * 4))
    )
      goto error;
    str = &show_table_status[0 + (2 * roop_count)];
    str->q_append(
      SPIDER_SQL_SHOW_TABLE_STATUS_STR, SPIDER_SQL_SHOW_TABLE_STATUS_LEN);
    str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    str->q_append(db_names_str[roop_count].ptr(),
      db_names_str[roop_count].length());
    str->q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    str->q_append(SPIDER_SQL_LIKE_STR, SPIDER_SQL_LIKE_LEN);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(table_names_str[roop_count].ptr(),
      table_names_str[roop_count].length());
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str = &show_table_status[1 + (2 * roop_count)];
    str->q_append(
      SPIDER_SQL_SELECT_TABLES_STATUS_STR,
      SPIDER_SQL_SELECT_TABLES_STATUS_LEN);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(db_names_str[roop_count].ptr(),
      db_names_str[roop_count].length());
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
    str->q_append(SPIDER_SQL_TABLE_NAME_STR, SPIDER_SQL_TABLE_NAME_LEN);
    str->q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(table_names_str[roop_count].ptr(),
      table_names_str[roop_count].length());
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  }
  DBUG_RETURN(0);

error:
  if (show_table_status)
  {
    delete [] show_table_status;
    show_table_status = NULL;
  }
  DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}

void spider_mbase_share::free_show_table_status()
{
  DBUG_ENTER("spider_mysql_free_show_table_status");
  if (show_table_status)
  {
    delete [] show_table_status;
    show_table_status = NULL;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_share::append_show_records()
{
  int roop_count;
  spider_string *str;
  DBUG_ENTER("spider_mbase_share::append_show_records");
  if (!(show_records = new spider_string[spider_share->all_link_count]))
    goto error;

  for (roop_count = 0; roop_count < (int) spider_share->all_link_count;
    roop_count++)
  {
    show_records[roop_count].init_calc_mem(SPD_MID_MBASE_SHARE_APPEND_SHOW_RECORDS_1);
    if (spider_share->sql_dbton_ids[roop_count] != dbton_id)
      continue;

    if (
      show_records[roop_count].reserve(
        SPIDER_SQL_SHOW_RECORDS_LEN +
        db_names_str[roop_count].length() +
        SPIDER_SQL_DOT_LEN +
        table_names_str[roop_count].length() +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 4)
    )
      goto error;
    str = &show_records[roop_count];
    str->q_append(SPIDER_SQL_SHOW_RECORDS_STR, SPIDER_SQL_SHOW_RECORDS_LEN);
    append_table_name(str, roop_count);
  }
  DBUG_RETURN(0);

error:
  if (show_records)
  {
    delete [] show_records;
    show_records = NULL;
  }
  DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}

void spider_mbase_share::free_show_records()
{
  DBUG_ENTER("spider_mbase_share::free_show_records");
  if (show_records)
  {
    delete [] show_records;
    show_records = NULL;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_share::append_show_index()
{
  int roop_count;
  spider_string *str;
  DBUG_ENTER("spider_mbase_share::append_show_index");
  if (!(show_index = new spider_string[2 * spider_share->all_link_count]))
    goto error;

  for (roop_count = 0; roop_count < (int) spider_share->all_link_count;
    roop_count++)
  {
    show_index[0 + (2 * roop_count)].init_calc_mem(SPD_MID_MBASE_SHARE_APPEND_SHOW_INDEX_1);
    show_index[1 + (2 * roop_count)].init_calc_mem(SPD_MID_MBASE_SHARE_APPEND_SHOW_INDEX_2);
    if (spider_share->sql_dbton_ids[roop_count] != dbton_id)
      continue;

    if (
      show_index[0 + (2 * roop_count)].reserve(
        SPIDER_SQL_SHOW_INDEX_LEN + db_names_str[roop_count].length() +
        SPIDER_SQL_DOT_LEN +
        table_names_str[roop_count].length() +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 4) ||
      show_index[1 + (2 * roop_count)].reserve(
        SPIDER_SQL_SELECT_STATISTICS_LEN +
        db_names_str[roop_count].length() +
        SPIDER_SQL_AND_LEN + SPIDER_SQL_TABLE_NAME_LEN + SPIDER_SQL_EQUAL_LEN +
        table_names_str[roop_count].length() +
        ((SPIDER_SQL_VALUE_QUOTE_LEN) * 4) +
        SPIDER_SQL_GROUP_LEN + SPIDER_SQL_COLUMN_NAME_LEN)
    )
      goto error;
    str = &show_index[0 + (2 * roop_count)];
    str->q_append(
      SPIDER_SQL_SHOW_INDEX_STR, SPIDER_SQL_SHOW_INDEX_LEN);
    append_table_name(str, roop_count);
    str = &show_index[1 + (2 * roop_count)];
    str->q_append(
      SPIDER_SQL_SELECT_STATISTICS_STR, SPIDER_SQL_SELECT_STATISTICS_LEN);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(db_names_str[roop_count].ptr(),
      db_names_str[roop_count].length());
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
    str->q_append(SPIDER_SQL_TABLE_NAME_STR, SPIDER_SQL_TABLE_NAME_LEN);
    str->q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN);
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(table_names_str[roop_count].ptr(),
      table_names_str[roop_count].length());
    str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    str->q_append(SPIDER_SQL_GROUP_STR, SPIDER_SQL_GROUP_LEN);
    str->q_append(SPIDER_SQL_COLUMN_NAME_STR, SPIDER_SQL_COLUMN_NAME_LEN);
  }
  DBUG_RETURN(0);

error:
  if (show_index)
  {
    delete [] show_index;
    show_index = NULL;
  }
  DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}

void spider_mbase_share::free_show_index()
{
  DBUG_ENTER("spider_mbase_share::free_show_index");
  if (show_index)
  {
    delete [] show_index;
    show_index = NULL;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_share::append_table_select()
{
  Field **field;
  uint field_length;
  spider_string *str = table_select;
  TABLE_SHARE *table_share = spider_share->table_share;
  DBUG_ENTER("spider_mbase_share::append_table_select");

  if (!*table_share->field)
    DBUG_RETURN(0);

  for (field = table_share->field; *field; field++)
  {
    field_length = column_name_str[(*field)->field_index].length();
    if (str->reserve(field_length +
      /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    append_column_name(str, (*field)->field_index);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(append_from_with_adjusted_table_name(str, &table_select_pos));
}

int spider_mbase_share::append_key_select(
  uint idx
) {
  KEY_PART_INFO *key_part;
  Field *field;
  uint part_num;
  uint field_length;
  spider_string *str = &key_select[idx];
  TABLE_SHARE *table_share = spider_share->table_share;
  const KEY *key_info = &table_share->key_info[idx];
  DBUG_ENTER("spider_mbase_share::append_key_select");

  if (!spider_user_defined_key_parts(key_info))
    DBUG_RETURN(0);

  for (key_part = key_info->key_part, part_num = 0;
    part_num < spider_user_defined_key_parts(key_info); key_part++, part_num++)
  {
    field = key_part->field;
    field_length = column_name_str[field->field_index].length();
    if (str->reserve(field_length +
      /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    append_column_name(str, field->field_index);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(append_from_with_adjusted_table_name(str, &key_select_pos[idx]));
}

bool spider_mbase_share::need_change_db_table_name()
{
  DBUG_ENTER("spider_mbase_share::need_change_db_table_name");
  DBUG_RETURN(!same_db_table_name);
}

int spider_mbase_share::discover_table_structure(
  SPIDER_TRX *trx,
  SPIDER_SHARE *spider_share,
  spider_string *str
) {
  int roop_count, error_num = HA_ERR_WRONG_COMMAND;
  char sql_buf[MAX_FIELD_WIDTH];
  spider_string sql_str(sql_buf, sizeof(sql_buf), system_charset_info);
  uint strlen = str->length();
  DBUG_ENTER("spider_mbase_share::discover_table_structure");
  DBUG_PRINT("info",("spider this=%p", this));
  sql_str.init_calc_mem(SPD_MID_MBASE_SHARE_DISCOVER_TABLE_STRUCTURE_1);
  for (roop_count = 0; roop_count < (int) spider_share->all_link_count;
    roop_count++)
  {
    if (spider_share->sql_dbton_ids[roop_count] != dbton_id)
    {
      DBUG_PRINT("info",("spider spider_share->sql_dbton_ids[%d]=%u",
        roop_count, spider_share->sql_dbton_ids[roop_count]));
      DBUG_PRINT("info",("spider dbton_id=%u", dbton_id));
      continue;
    }

    str->length(strlen);
    sql_str.length(0);
    if (sql_str.reserve(
      SPIDER_SQL_SELECT_COLUMNS_LEN + db_names_str[roop_count].length() +
      SPIDER_SQL_AND_LEN + SPIDER_SQL_TABLE_NAME_LEN + SPIDER_SQL_EQUAL_LEN +
      table_names_str[roop_count].length() + SPIDER_SQL_ORDER_LEN +
      SPIDER_SQL_ORDINAL_POSITION_LEN +
      /* SPIDER_SQL_VALUE_QUOTE_LEN */ 8 +
      SPIDER_SQL_SEMICOLON_LEN +
      SPIDER_SQL_SHOW_INDEX_LEN + db_names_str[roop_count].length() +
      SPIDER_SQL_DOT_LEN + table_names_str[roop_count].length() +
      /* SPIDER_SQL_NAME_QUOTE_LEN */ 4 +
      SPIDER_SQL_SEMICOLON_LEN +
      SPIDER_SQL_SHOW_TABLE_STATUS_LEN + db_names_str[roop_count].length() +
      SPIDER_SQL_LIKE_LEN + table_names_str[roop_count].length() +
      /* SPIDER_SQL_NAME_QUOTE_LEN */ 4
    )) {
      DBUG_PRINT("info",("spider alloc sql_str error"));
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    sql_str.q_append(SPIDER_SQL_SELECT_COLUMNS_STR,
      SPIDER_SQL_SELECT_COLUMNS_LEN);
    sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    sql_str.q_append(db_names_str[roop_count].ptr(),
      db_names_str[roop_count].length());
    sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    sql_str.q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
    sql_str.q_append(SPIDER_SQL_TABLE_NAME_STR, SPIDER_SQL_TABLE_NAME_LEN);
    sql_str.q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN);
    sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    sql_str.q_append(table_names_str[roop_count].ptr(),
      table_names_str[roop_count].length());
    sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    sql_str.q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
    sql_str.q_append(SPIDER_SQL_ORDINAL_POSITION_STR,
      SPIDER_SQL_ORDINAL_POSITION_LEN);
    sql_str.q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
    sql_str.q_append(SPIDER_SQL_SHOW_INDEX_STR, SPIDER_SQL_SHOW_INDEX_LEN);
    append_table_name(&sql_str, roop_count);
    sql_str.q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
    sql_str.q_append(
      SPIDER_SQL_SHOW_TABLE_STATUS_STR, SPIDER_SQL_SHOW_TABLE_STATUS_LEN);
    sql_str.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    sql_str.q_append(db_names_str[roop_count].ptr(),
      db_names_str[roop_count].length());
    sql_str.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    sql_str.q_append(SPIDER_SQL_LIKE_STR, SPIDER_SQL_LIKE_LEN);
    sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    sql_str.q_append(table_names_str[roop_count].ptr(),
      table_names_str[roop_count].length());
    sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);

    SPIDER_CONN *conn;
    int need_mon_deref;
    int *need_mon= &need_mon_deref;
    if (!(conn = spider_get_conn(
      spider_share, 0, spider_share->conn_keys[roop_count], trx, NULL, FALSE,
      FALSE, &error_num))
    ) {
      DBUG_RETURN(error_num);
    }
    spider_lock_before_query(conn, need_mon);
    if (!conn->disable_reconnect)
    {
      ha_spider tmp_spider;
      SPIDER_WIDE_HANDLER wide_handler;
      int need_mon= 0;
      uint tmp_conn_link_idx= 0;
      tmp_spider.wide_handler= &wide_handler;
      wide_handler.trx= trx;
      tmp_spider.share= spider_share;
      tmp_spider.need_mons= &need_mon;
      tmp_spider.conn_link_idx= &tmp_conn_link_idx;
      if ((error_num= spider_db_ping(&tmp_spider, conn, 0)))
      {
        spider_unlock_after_query(conn, 0);
        continue;
      }
    }
    spider_conn_set_timeout_from_share(conn, roop_count, trx->thd,
                                         spider_share);
    if ((error_num= spider_db_set_names_internal(trx, spider_share, conn,
                                                 roop_count, need_mon)) ||
        (spider_db_query(conn, sql_str.ptr(), sql_str.length(), -1,
                         need_mon) &&
         (error_num= spider_db_errorno(conn))))
    {
      spider_unlock_after_query(conn, 0);
      continue;
    }
    st_spider_db_request_key request_key;
    request_key.spider_thread_id= trx->spider_thread_id;
    request_key.query_id= trx->thd->query_id; request_key.handler= NULL;
    request_key.request_id= 1; request_key.next= NULL;
    spider_db_result * res;
    /* get column list */
    if (!(res= conn->db_conn->store_result(NULL, &request_key,
                                           &error_num))) {
      if (error_num || (error_num= spider_db_errorno(conn)))
      {
        spider_unlock_after_query(conn, 0);
        continue;
      }
      spider_unlock_after_query(conn, 0);
      continue;
    }
    if ((error_num=
         res->fetch_columns_for_discover_table_structure(
           str, spider_share->access_charset))) {
      DBUG_PRINT("info", ("spider column fetch error"));
      res->free_result();
      delete res;
      /*
        Use ErrConvString as db_names_str and table_names_str
        are not necessarily 0-terminated.
      */
      my_printf_error(ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM,
        ER_SPIDER_REMOTE_TABLE_NOT_FOUND_STR, MYF(0),
        ErrConvString(db_names_str[roop_count].ptr(),
                      db_names_str[roop_count].length(),
                      Lex_ident_db::charset_info()).ptr(),
        ErrConvString(table_names_str[roop_count].ptr(),
                      table_names_str[roop_count].length(),
                      Lex_ident_table::charset_info()).ptr());
      error_num = ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM;
      spider_unlock_after_query(conn, 0);
      continue;
    }
    res->free_result();
    delete res;
    if (conn->db_conn->next_result())
    {
      spider_unlock_after_query(conn, 0);
      continue;
    }
    /* get index list */
    if (!(res= conn->db_conn->store_result(NULL, &request_key,
                                           &error_num))) {
      if (error_num || (error_num= spider_db_errorno(conn)))
      {
        spider_unlock_after_query(conn, 0);
        continue;
      }
      spider_unlock_after_query(conn, 0);
      continue;
    }
    if ((error_num=
         res->fetch_index_for_discover_table_structure(
           str, spider_share->access_charset))) {
      DBUG_PRINT("info", ("spider index fetch error"));
      res->free_result();
      delete res;
      spider_unlock_after_query(conn, 0);
      continue;
    }
    res->free_result();
    delete res;
    if (conn->db_conn->next_result()) {
      DBUG_PRINT("info", ("spider dual result error"));
      spider_unlock_after_query(conn, 0);
      continue;
    }
    /* get table info */
    if (!(res = conn->db_conn->store_result(NULL, &request_key, &error_num)))
    {
      if (error_num || (error_num = spider_db_errorno(conn)))
      {
        DBUG_PRINT("info",("spider table store error"));
        spider_unlock_after_query(conn, 0);
        continue;
      }
      /* no record */
      DBUG_PRINT("info",("spider table no record error"));
      spider_unlock_after_query(conn, 0);
      continue;
    }
    if ((error_num = res->fetch_table_for_discover_table_structure(str,
     spider_share, spider_share->access_charset)))
    {
      DBUG_PRINT("info",("spider table fetch error"));
      res->free_result();
      delete res;
      spider_unlock_after_query(conn, 0);
      continue;
    }
    res->free_result();
    delete res;
    if (!error_num)
    {
      spider_unlock_after_query(conn, 0);
      break;
    }
  }
  DBUG_RETURN(error_num);
}

bool spider_mbase_share::checksum_support()
{
  DBUG_ENTER("spider_mbase_share::checksum_support");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

spider_mbase_handler::spider_mbase_handler(
  ha_spider *spider,
  spider_mbase_share *db_share,
  spider_db_mbase_util *spider_db_mbase_utility
) : spider_db_handler(
  spider,
  db_share
),
  spider_db_mbase_utility(spider_db_mbase_utility),
  where_pos(0),
  order_pos(0),
  limit_pos(0),
  table_name_pos(0),
  ha_read_pos(0),
  ha_next_pos(0),
  ha_where_pos(0),
  ha_limit_pos(0),
  ha_table_name_pos(0),
  insert_pos(0),
  insert_table_name_pos(0),
  upd_tmp_tbl(NULL),
  tmp_sql_pos1(0),
  tmp_sql_pos2(0),
  tmp_sql_pos3(0),
  tmp_sql_pos4(0),
  tmp_sql_pos5(0),
  reading_from_bulk_tmp_table(FALSE),
  union_table_name_pos_first(NULL),
  union_table_name_pos_current(NULL),
  mysql_share(db_share),
  link_for_hash(NULL)
{
  DBUG_ENTER("spider_mbase_handler::spider_mbase_handler");
  DBUG_PRINT("info",("spider this=%p", this));
  spider_alloc_calc_mem_init(mem_calc, SPD_MID_MBASE_HANDLER_SPIDER_MBASE_HANDLER_1);
  spider_alloc_calc_mem(spider_current_trx, mem_calc, sizeof(*this));
  DBUG_VOID_RETURN;
}

spider_mysql_handler::spider_mysql_handler(
  ha_spider *spider,
  spider_mbase_share *db_share
) : spider_mbase_handler(
  spider,
  db_share,
  &spider_db_mysql_utility
) {
  DBUG_ENTER("spider_mysql_handler::spider_mysql_handler");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mariadb_handler::spider_mariadb_handler(
  ha_spider *spider,
  spider_mbase_share *db_share
) : spider_mbase_handler(
  spider,
  db_share,
  &spider_db_mariadb_utility
) {
  DBUG_ENTER("spider_mariadb_handler::spider_mariadb_handler");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mbase_handler::~spider_mbase_handler()
{
  DBUG_ENTER("spider_mbase_handler::~spider_mbase_handler");
  DBUG_PRINT("info",("spider this=%p", this));
  while (union_table_name_pos_first)
  {
    SPIDER_INT_HLD *tmp_pos = union_table_name_pos_first;
    union_table_name_pos_first = tmp_pos->next;
    spider_free(spider_current_trx, tmp_pos, MYF(0));
  }
  if (link_for_hash)
  {
    spider_free(spider_current_trx, link_for_hash, MYF(0));
  }
  spider_free_mem_calc(spider_current_trx, mem_calc_id, sizeof(*this));
  DBUG_VOID_RETURN;
}

spider_mysql_handler::~spider_mysql_handler()
{
  DBUG_ENTER("spider_mysql_handler::~spider_mysql_handler");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mariadb_handler::~spider_mariadb_handler()
{
  DBUG_ENTER("spider_mariadb_handler::~spider_mariadb_handler");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

int spider_mbase_handler::init()
{
  uint roop_count;
  THD *thd = spider->wide_handler->trx->thd;
  st_spider_share *share = spider->share;
  int init_sql_alloc_size =
    spider_param_init_sql_alloc_size(thd, share->init_sql_alloc_size);
  TABLE *table = spider->get_table();
  DBUG_ENTER("spider_mbase_handler::init");
  DBUG_PRINT("info",("spider this=%p", this));
  sql.init_calc_mem(SPD_MID_MBASE_HANDLER_INIT_1);
  sql_part.init_calc_mem(SPD_MID_MBASE_HANDLER_INIT_2);
  sql_part2.init_calc_mem(SPD_MID_MBASE_HANDLER_INIT_3);
  ha_sql.init_calc_mem(SPD_MID_MBASE_HANDLER_INIT_4);
  insert_sql.init_calc_mem(SPD_MID_MBASE_HANDLER_INIT_5);
  update_sql.init_calc_mem(SPD_MID_MBASE_HANDLER_INIT_6);
  tmp_sql.init_calc_mem(SPD_MID_MBASE_HANDLER_INIT_7);
  dup_update_sql.init_calc_mem(SPD_MID_MBASE_HANDLER_INIT_8);
  if (
    (sql.real_alloc(init_sql_alloc_size)) ||
    (insert_sql.real_alloc(init_sql_alloc_size)) ||
    (update_sql.real_alloc(init_sql_alloc_size)) ||
    (tmp_sql.real_alloc(init_sql_alloc_size))
  ) {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  sql.set_charset(share->access_charset);
  sql_part.set_charset(share->access_charset);
  sql_part2.set_charset(share->access_charset);
  ha_sql.set_charset(share->access_charset);
  insert_sql.set_charset(share->access_charset);
  update_sql.set_charset(share->access_charset);
  tmp_sql.set_charset(share->access_charset);
  dup_update_sql.set_charset(share->access_charset);
  upd_tmp_tbl_prm.init();
  upd_tmp_tbl_prm.field_count = 1;
  if (!(link_for_hash = (SPIDER_LINK_FOR_HASH *)
    spider_bulk_alloc_mem(spider_current_trx, SPD_MID_MBASE_HANDLER_INIT_9,
      __func__, __FILE__, __LINE__, MYF(MY_WME | MY_ZEROFILL),
      &link_for_hash,
        sizeof(SPIDER_LINK_FOR_HASH) * share->link_count,
      &minimum_select_bitmap,
        table ? sizeof(uchar) * my_bitmap_buffer_size(table->read_set) : 0,
      NullS))
  ) {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  for (roop_count = 0; roop_count < share->link_count; roop_count++)
  {
    link_for_hash[roop_count].spider = spider;
    link_for_hash[roop_count].link_idx = roop_count;
    link_for_hash[roop_count].db_table_str =
      &mysql_share->db_table_str[roop_count];
    link_for_hash[roop_count].db_table_str_hash_value =
      mysql_share->db_table_str_hash_value[roop_count];
  }
  DBUG_RETURN(0);
}


int spider_mbase_handler::append_index_hint(
  spider_string *str,
  int link_idx,
  ulong sql_type
  )
{
  List<Index_hint> *index_hints = spider_get_index_hints(spider);
  List_iterator <Index_hint> iter(*index_hints);
  Index_hint *hint;
//  THD *thd = current_thd;
  int error_num = 0;
  DBUG_ENTER("spider_mbase_handler::append_index_hint");
  DBUG_PRINT("info",("spider this=%p", this));

  while(index_hints && (hint = iter++))
  {
    {
      switch(hint->type)
      {
      case INDEX_HINT_IGNORE:
        if (str->reserve(hint->key_name.length+ SPIDER_SQL_INDEX_IGNORE_LEN + SPIDER_SQL_OPEN_PAREN_LEN + SPIDER_SQL_CLOSE_PAREN_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_INDEX_IGNORE_STR,SPIDER_SQL_INDEX_IGNORE_LEN);
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR,SPIDER_SQL_OPEN_PAREN_LEN);
        str->q_append(hint->key_name.str, hint->key_name.length);
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,SPIDER_SQL_CLOSE_PAREN_LEN);
        break;
      case INDEX_HINT_USE:
        if (str->reserve(hint->key_name.length+ SPIDER_SQL_INDEX_USE_LEN + SPIDER_SQL_OPEN_PAREN_LEN + SPIDER_SQL_CLOSE_PAREN_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_INDEX_USE_STR,SPIDER_SQL_INDEX_USE_LEN);
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR,SPIDER_SQL_OPEN_PAREN_LEN);
        str->q_append(hint->key_name.str, hint->key_name.length);
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,SPIDER_SQL_CLOSE_PAREN_LEN);
        break;
      case INDEX_HINT_FORCE:
        if (str->reserve(hint->key_name.length+ SPIDER_SQL_INDEX_FORCE_LEN + SPIDER_SQL_OPEN_PAREN_LEN + SPIDER_SQL_CLOSE_PAREN_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_INDEX_FORCE_STR,SPIDER_SQL_INDEX_FORCE_LEN);
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR,SPIDER_SQL_OPEN_PAREN_LEN);
        str->q_append(hint->key_name.str, hint->key_name.length);
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR,SPIDER_SQL_CLOSE_PAREN_LEN);
        break;
      default:
        //    SPIDER_SQL_COMMA_STR
        break;
      }
    }
  }
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_table_name_with_adjusting(
  spider_string *str,
  int link_idx,
  ulong sql_type
) {
  int error_num = 0;
  DBUG_ENTER("spider_mbase_handler::append_table_name_with_adjusting");
  DBUG_PRINT("info",("spider this=%p", this));
    error_num = mysql_share->append_table_name_with_adjusting(str,
      spider->conn_link_idx[link_idx]);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_key_column_types(
  const key_range *start_key,
  spider_string *str
) {
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  KEY *key_info = result_list->key_info;
  uint key_name_length, key_count;
  key_part_map full_key_part_map =
    make_prev_keypart_map(spider_user_defined_key_parts(key_info));
  key_part_map start_key_part_map;
  KEY_PART_INFO *key_part;
  Field *field;
  char tmp_buf[MAX_FIELD_WIDTH];
  spider_string tmp_str(tmp_buf, sizeof(tmp_buf), system_charset_info);
  DBUG_ENTER("spider_mbase_handler::append_key_column_types");
  DBUG_PRINT("info",("spider this=%p", this));
  tmp_str.init_calc_mem(SPD_MID_MBASE_HANDLER_APPEND_KEY_COLUMN_TYPES_1);

  start_key_part_map = start_key->keypart_map & full_key_part_map;
  DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u",
    spider_user_defined_key_parts(key_info)));
  DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map));
  DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map));

  if (!start_key_part_map)
    DBUG_RETURN(0);

  for (
    key_part = key_info->key_part,
    key_count = 0;
    start_key_part_map;
    start_key_part_map >>= 1,
    key_part++,
    key_count++
  ) {
    field = key_part->field;
    key_name_length = my_sprintf(tmp_buf, (tmp_buf, "c%u", key_count));
    if (str->reserve(key_name_length + SPIDER_SQL_SPACE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(tmp_buf, key_name_length);
    str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);

    if (tmp_str.ptr() != tmp_buf)
      tmp_str.set(tmp_buf, sizeof(tmp_buf), system_charset_info);
    else
      tmp_str.set_charset(system_charset_info);
    field->sql_type(*tmp_str.get_str());
    tmp_str.mem_calc();
    str->append(tmp_str);
    if (field->has_charset())
    {
      CHARSET_INFO *cs = field->charset();
      uint coll_length = cs->coll_name.length;
      if (str->reserve(SPIDER_SQL_COLLATE_LEN + coll_length))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_COLLATE_STR, SPIDER_SQL_COLLATE_LEN);
      str->q_append(cs->coll_name.str, coll_length);
    }

    if (str->reserve(SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);

  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_join_columns_for_bka(
  const key_range *start_key,
  spider_string *str,
  const char **table_aliases,
  uint *table_alias_lengths
) {
  KEY *key_info = spider->result_list.key_info;
  uint length, key_name_length, key_count;
  key_part_map full_key_part_map =
    make_prev_keypart_map(spider_user_defined_key_parts(key_info));
  key_part_map start_key_part_map;
  KEY_PART_INFO *key_part;
  Field *field;
  char tmp_buf[MAX_FIELD_WIDTH];
  bool start_where = ((int) str->length() == where_pos);
  DBUG_ENTER("spider_mbase_handler::append_key_join_columns_for_bka");
  DBUG_PRINT("info",("spider this=%p", this));
  start_key_part_map = start_key->keypart_map & full_key_part_map;
  DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u",
    spider_user_defined_key_parts(key_info)));
  DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map));
  DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map));

  if (!start_key_part_map)
    DBUG_RETURN(0);

  if (start_where)
  {
    if (str->reserve(SPIDER_SQL_WHERE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_WHERE_STR, SPIDER_SQL_WHERE_LEN);
  } else {
    if (str->reserve(SPIDER_SQL_AND_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
  }

  for (
    key_part = key_info->key_part,
    key_count = 0;
    start_key_part_map;
    start_key_part_map >>= 1,
    key_part++,
    key_count++
  ) {
    field = key_part->field;
    key_name_length =
      mysql_share->column_name_str[field->field_index].length();
    length = my_sprintf(tmp_buf, (tmp_buf, "c%u", key_count));
    if (str->reserve(length + table_alias_lengths[0] + key_name_length +
      /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
      table_alias_lengths[1] + SPIDER_SQL_PF_EQUAL_LEN + SPIDER_SQL_AND_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(table_aliases[0], table_alias_lengths[0]);
    str->q_append(tmp_buf, length);
    str->q_append(SPIDER_SQL_PF_EQUAL_STR, SPIDER_SQL_PF_EQUAL_LEN);
    str->q_append(table_aliases[1], table_alias_lengths[1]);
    mysql_share->append_column_name(str, field->field_index);
    str->q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
  }
  str->length(str->length() - SPIDER_SQL_AND_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_tmp_table_and_sql_for_bka(
  const key_range *start_key
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_tmp_table_and_sql_for_bka");
  DBUG_PRINT("info",("spider this=%p", this));
  char tmp_table_name[MAX_FIELD_WIDTH * 2],
    tgt_table_name[MAX_FIELD_WIDTH * 2];
  int tmp_table_name_length;
  spider_string tgt_table_name_str(tgt_table_name, MAX_FIELD_WIDTH * 2,
    mysql_share->db_names_str[0].charset());
  const char *table_names[2], *table_aliases[2], *table_dot_aliases[2];
  uint table_name_lengths[2], table_alias_lengths[2],
    table_dot_alias_lengths[2];
  tgt_table_name_str.init_calc_mem(SPD_MID_MBASE_HANDLER_APPEND_TMP_TABLE_AND_SQL_FOR_BKA_1);
  tgt_table_name_str.length(0);
  create_tmp_bka_table_name(tmp_table_name, &tmp_table_name_length,
    first_link_idx);
  if ((error_num = append_table_name_with_adjusting(&tgt_table_name_str,
    first_link_idx, SPIDER_SQL_TYPE_SELECT_SQL)))
  {
    DBUG_RETURN(error_num);
  }
  table_names[0] = tmp_table_name;
  table_names[1] = tgt_table_name_str.c_ptr_safe();
  table_name_lengths[0] = tmp_table_name_length;
  table_name_lengths[1] = tgt_table_name_str.length();
  table_aliases[0] = SPIDER_SQL_A_STR;
  table_aliases[1] = SPIDER_SQL_B_STR;
  table_alias_lengths[0] = SPIDER_SQL_A_LEN;
  table_alias_lengths[1] = SPIDER_SQL_B_LEN;
  table_dot_aliases[0] = SPIDER_SQL_A_DOT_STR;
  table_dot_aliases[1] = SPIDER_SQL_B_DOT_STR;
  table_dot_alias_lengths[0] = SPIDER_SQL_A_DOT_LEN;
  table_dot_alias_lengths[1] = SPIDER_SQL_B_DOT_LEN;
  if (
    (error_num = append_drop_tmp_bka_table(
      &tmp_sql, tmp_table_name, tmp_table_name_length,
      &tmp_sql_pos1, &tmp_sql_pos5, TRUE)) ||
    (error_num = append_create_tmp_bka_table(
      start_key,
      &tmp_sql, tmp_table_name,
      tmp_table_name_length,
      &tmp_sql_pos2, spider->share->table_share->table_charset)) ||
    (error_num = append_insert_tmp_bka_table(
      start_key,
      &tmp_sql, tmp_table_name,
      tmp_table_name_length, &tmp_sql_pos3))
  )
    DBUG_RETURN(error_num);
  tmp_sql_pos4 = tmp_sql.length();
  if ((error_num = spider_db_append_select(spider)))
    DBUG_RETURN(error_num);
  if (sql.reserve(SPIDER_SQL_A_DOT_LEN + SPIDER_SQL_ID_LEN +
    SPIDER_SQL_COMMA_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_A_DOT_STR, SPIDER_SQL_A_DOT_LEN);
  sql.q_append(SPIDER_SQL_ID_STR, SPIDER_SQL_ID_LEN);
  sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  if (
    (error_num = append_select_columns_with_alias(&sql,
      SPIDER_SQL_B_DOT_STR, SPIDER_SQL_B_DOT_LEN)) ||
    (error_num = spider_db_mbase_utility->append_from_with_alias(&sql,
      table_names, table_name_lengths,
      table_aliases, table_alias_lengths, 2,
      &table_name_pos, FALSE))
  )
    DBUG_RETURN(error_num);
  if (
    mysql_share->key_hint &&
    (error_num = spider_db_append_hint_after_table(spider,
      &sql, &mysql_share->key_hint[spider->active_index]))
  )
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  where_pos = sql.length();
  if (
    (error_num = append_key_join_columns_for_bka(
      start_key, &sql,
      table_dot_aliases, table_dot_alias_lengths)) ||
    (error_num = append_condition_part(
      SPIDER_SQL_B_DOT_STR, SPIDER_SQL_B_DOT_LEN,
      SPIDER_SQL_TYPE_SELECT_SQL, FALSE))
  )
    DBUG_RETURN(error_num);
  if (spider->result_list.direct_order_limit)
  {
    if ((error_num = append_key_order_for_direct_order_limit_with_alias(&sql,
      SPIDER_SQL_B_DOT_STR, SPIDER_SQL_B_DOT_LEN)))
      DBUG_RETURN(error_num);
  }
  else if (spider->result_list.direct_aggregate)
  {
    if ((error_num =
      append_group_by(&sql, SPIDER_SQL_B_DOT_STR, SPIDER_SQL_B_DOT_LEN)))
      DBUG_RETURN(error_num);
  }

  DBUG_RETURN(0);
}

int spider_mbase_handler::reuse_tmp_table_and_sql_for_bka()
{
  DBUG_ENTER("spider_mbase_handler::reuse_tmp_table_and_sql_for_bka");
  DBUG_PRINT("info",("spider this=%p", this));
  tmp_sql.length(tmp_sql_pos4);
  sql.length(limit_pos);
  ha_sql.length(ha_limit_pos);
  DBUG_RETURN(0);
}

void spider_mbase_handler::create_tmp_bka_table_name(
  char *tmp_table_name,
  int *tmp_table_name_length,
  int link_idx
) {
  uint adjust_length, length;
  DBUG_ENTER("spider_mbase_handler::create_tmp_bka_table_name");
  if (spider_param_bka_table_name_type(current_thd,
    mysql_share->spider_share->
      bka_table_name_types[spider->conn_link_idx[link_idx]]) == 1)
  {
    adjust_length =
      mysql_share->db_nm_max_length -
      mysql_share->db_names_str[spider->conn_link_idx[link_idx]].length() +
      mysql_share->table_nm_max_length -
      mysql_share->table_names_str[spider->conn_link_idx[link_idx]].length();
    *tmp_table_name_length = mysql_share->db_nm_max_length +
      mysql_share->table_nm_max_length;
    memset(tmp_table_name, ' ', adjust_length);
    tmp_table_name += adjust_length;
    memcpy(tmp_table_name, mysql_share->db_names_str[link_idx].c_ptr(),
      mysql_share->db_names_str[link_idx].length());
    tmp_table_name += mysql_share->db_names_str[link_idx].length();
    length = my_sprintf(tmp_table_name, (tmp_table_name,
      "%s%s%p%s", SPIDER_SQL_DOT_STR, SPIDER_SQL_TMP_BKA_STR, spider,
      SPIDER_SQL_UNDERSCORE_STR));
    *tmp_table_name_length += length;
    tmp_table_name += length;
    memcpy(tmp_table_name,
      mysql_share->table_names_str[spider->conn_link_idx[link_idx]].c_ptr(),
      mysql_share->table_names_str[spider->conn_link_idx[link_idx]].length());
  } else {
    adjust_length =
      mysql_share->db_nm_max_length -
      mysql_share->db_names_str[spider->conn_link_idx[link_idx]].length();
    *tmp_table_name_length = mysql_share->db_nm_max_length;
    memset(tmp_table_name, ' ', adjust_length);
    tmp_table_name += adjust_length;
    memcpy(tmp_table_name, mysql_share->db_names_str[link_idx].c_ptr(),
      mysql_share->db_names_str[link_idx].length());
    tmp_table_name += mysql_share->db_names_str[link_idx].length();
    length = my_sprintf(tmp_table_name, (tmp_table_name,
      "%s%s%p", SPIDER_SQL_DOT_STR, SPIDER_SQL_TMP_BKA_STR, spider));
    *tmp_table_name_length += length;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_handler::append_create_tmp_bka_table(
  const key_range *start_key,
  spider_string *str,
  char *tmp_table_name,
  int tmp_table_name_length,
  int *db_name_pos,
  CHARSET_INFO *table_charset
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  THD *thd = spider->wide_handler->trx->thd;
  char *bka_engine = spider_param_bka_engine(thd, share->bka_engine);
  uint bka_engine_length = strlen(bka_engine),
    cset_length = table_charset->cs_name.length,
    coll_length = table_charset->coll_name.length;
  DBUG_ENTER("spider_mbase_handler::append_create_tmp_bka_table");
  if (str->reserve(SPIDER_SQL_CREATE_TMP_LEN + tmp_table_name_length +
    SPIDER_SQL_OPEN_PAREN_LEN + SPIDER_SQL_ID_LEN + SPIDER_SQL_ID_TYPE_LEN +
    SPIDER_SQL_COMMA_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_CREATE_TMP_STR, SPIDER_SQL_CREATE_TMP_LEN);
  *db_name_pos = str->length();
  str->q_append(tmp_table_name, tmp_table_name_length);
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  str->q_append(SPIDER_SQL_ID_STR, SPIDER_SQL_ID_LEN);
  str->q_append(SPIDER_SQL_ID_TYPE_STR, SPIDER_SQL_ID_TYPE_LEN);
  str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  if ((error_num = append_key_column_types(start_key, str)))
    DBUG_RETURN(error_num);
  if (str->reserve(SPIDER_SQL_ENGINE_LEN + bka_engine_length +
    SPIDER_SQL_DEF_CHARSET_LEN + cset_length + SPIDER_SQL_COLLATE_LEN +
    coll_length + SPIDER_SQL_SEMICOLON_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_ENGINE_STR, SPIDER_SQL_ENGINE_LEN);
  str->q_append(bka_engine, bka_engine_length);
  str->q_append(SPIDER_SQL_DEF_CHARSET_STR, SPIDER_SQL_DEF_CHARSET_LEN);
  str->q_append(table_charset->cs_name.str, cset_length);
  str->q_append(SPIDER_SQL_COLLATE_STR, SPIDER_SQL_COLLATE_LEN);
  str->q_append(table_charset->coll_name.str, coll_length);
  str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_drop_tmp_bka_table(
  spider_string *str,
  char *tmp_table_name,
  int tmp_table_name_length,
  int *db_name_pos,
  int *drop_table_end_pos,
  bool with_semicolon
) {
  DBUG_ENTER("spider_mbase_handler::append_drop_tmp_bka_table");
  if (str->reserve(SPIDER_SQL_DROP_TMP_LEN + tmp_table_name_length +
    (with_semicolon ? SPIDER_SQL_SEMICOLON_LEN : 0)))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_DROP_TMP_STR, SPIDER_SQL_DROP_TMP_LEN);
  *db_name_pos = str->length();
  str->q_append(tmp_table_name, tmp_table_name_length);
  *drop_table_end_pos = str->length();
  if (with_semicolon)
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_insert_tmp_bka_table(
  const key_range *start_key,
  spider_string *str,
  char *tmp_table_name,
  int tmp_table_name_length,
  int *db_name_pos
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_insert_tmp_bka_table");
  if (str->reserve(SPIDER_SQL_INSERT_LEN + SPIDER_SQL_INTO_LEN +
    tmp_table_name_length + SPIDER_SQL_OPEN_PAREN_LEN + SPIDER_SQL_ID_LEN +
    SPIDER_SQL_COMMA_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_INSERT_STR, SPIDER_SQL_INSERT_LEN);
  str->q_append(SPIDER_SQL_INTO_STR, SPIDER_SQL_INTO_LEN);
  *db_name_pos = str->length();
  str->q_append(tmp_table_name, tmp_table_name_length);
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  str->q_append(SPIDER_SQL_ID_STR, SPIDER_SQL_ID_LEN);
  str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  if ((error_num = spider_db_append_key_columns(start_key, spider, str)))
    DBUG_RETURN(error_num);
  if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_VALUES_LEN +
    SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  str->q_append(SPIDER_SQL_VALUES_STR, SPIDER_SQL_VALUES_LEN);
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_union_table_and_sql_for_bka(
  const key_range *start_key
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_union_table_and_sql_for_bka");
  DBUG_PRINT("info",("spider this=%p", this));
  char tgt_table_name[MAX_FIELD_WIDTH * 2];
  spider_string tgt_table_name_str(tgt_table_name, MAX_FIELD_WIDTH * 2,
    mysql_share->db_names_str[0].charset());
  const char *table_names[2], *table_aliases[2], *table_dot_aliases[2];
  uint table_name_lengths[2], table_alias_lengths[2],
    table_dot_alias_lengths[2];
  tgt_table_name_str.init_calc_mem(SPD_MID_MBASE_HANDLER_APPEND_UNION_TABLE_AND_SQL_FOR_BKA_1);
  tgt_table_name_str.length(0);
  if ((error_num = append_table_name_with_adjusting(&tgt_table_name_str,
    first_link_idx, SPIDER_SQL_TYPE_SELECT_SQL)))
  {
    DBUG_RETURN(error_num);
  }
  table_names[0] = "";
  table_names[1] = tgt_table_name_str.c_ptr_safe();
  table_name_lengths[0] = 0;
  table_name_lengths[1] = tgt_table_name_str.length();
  table_aliases[0] = SPIDER_SQL_A_STR;
  table_aliases[1] = SPIDER_SQL_B_STR;
  table_alias_lengths[0] = SPIDER_SQL_A_LEN;
  table_alias_lengths[1] = SPIDER_SQL_B_LEN;
  table_dot_aliases[0] = SPIDER_SQL_A_DOT_STR;
  table_dot_aliases[1] = SPIDER_SQL_B_DOT_STR;
  table_dot_alias_lengths[0] = SPIDER_SQL_A_DOT_LEN;
  table_dot_alias_lengths[1] = SPIDER_SQL_B_DOT_LEN;

  if ((error_num = spider_db_append_select(spider)))
    DBUG_RETURN(error_num);
  if (sql.reserve(SPIDER_SQL_A_DOT_LEN + SPIDER_SQL_ID_LEN +
    SPIDER_SQL_COMMA_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_A_DOT_STR, SPIDER_SQL_A_DOT_LEN);
  sql.q_append(SPIDER_SQL_ID_STR, SPIDER_SQL_ID_LEN);
  sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  if ((error_num = append_select_columns_with_alias(&sql,
    SPIDER_SQL_B_DOT_STR, SPIDER_SQL_B_DOT_LEN)))
    DBUG_RETURN(error_num);
  if (sql.reserve(SPIDER_SQL_FROM_LEN + (SPIDER_SQL_OPEN_PAREN_LEN * 2)))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_FROM_STR, SPIDER_SQL_FROM_LEN);
  sql.q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  sql.q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  tmp_sql_pos1 = sql.length();

  if (
    (error_num = spider_db_mbase_utility->append_from_with_alias(&tmp_sql,
      table_names, table_name_lengths,
      table_aliases, table_alias_lengths, 2,
      &table_name_pos, FALSE))
  )
    DBUG_RETURN(error_num);
  if (
    mysql_share->key_hint &&
    (error_num = spider_db_append_hint_after_table(spider,
      &tmp_sql, &mysql_share->key_hint[spider->active_index]))
  )
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  where_pos = tmp_sql.length();
  if (
    (error_num = append_key_join_columns_for_bka(
      start_key, &tmp_sql,
      table_dot_aliases, table_dot_alias_lengths)) ||
    (error_num = append_condition_part(
      SPIDER_SQL_B_DOT_STR, SPIDER_SQL_B_DOT_LEN,
      SPIDER_SQL_TYPE_TMP_SQL, FALSE))
  )
    DBUG_RETURN(error_num);
  if (spider->result_list.direct_order_limit)
  {
    if ((error_num =
      append_key_order_for_direct_order_limit_with_alias(&tmp_sql,
        SPIDER_SQL_B_DOT_STR, SPIDER_SQL_B_DOT_LEN))
    )
      DBUG_RETURN(error_num);
  }
  else if (spider->result_list.direct_aggregate)
  {
    if ((error_num =
      append_group_by(&tmp_sql, SPIDER_SQL_B_DOT_STR, SPIDER_SQL_B_DOT_LEN)))
      DBUG_RETURN(error_num);
  }

  DBUG_RETURN(0);
}

int spider_mbase_handler::reuse_union_table_and_sql_for_bka()
{
  DBUG_ENTER("spider_mbase_handler::reuse_union_table_and_sql_for_bka");
  DBUG_PRINT("info",("spider this=%p", this));
  sql.length(tmp_sql_pos1);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_insert_for_recovery(
  ulong sql_type,
  int link_idx
) {
  const TABLE *table = spider->get_table();
  SPIDER_SHARE *share = spider->share;
  Field **field;
  uint field_name_length = 0;
  bool add_value = FALSE;
  spider_string *insert_sql;
  DBUG_ENTER("spider_mbase_handler::append_insert_for_recovery");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql_type == SPIDER_SQL_TYPE_INSERT_SQL)
  {
    insert_sql = &spider->result_list.insert_sqls[link_idx];
    insert_sql->length(0);
  } else {
    insert_sql = &spider->result_list.update_sqls[link_idx];
  }
  if (insert_sql->reserve(
    SPIDER_SQL_INSERT_LEN + SPIDER_SQL_SQL_IGNORE_LEN +
    SPIDER_SQL_INTO_LEN + mysql_share->db_nm_max_length +
    SPIDER_SQL_DOT_LEN + mysql_share->table_nm_max_length +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4 + SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  insert_sql->q_append(SPIDER_SQL_INSERT_STR, SPIDER_SQL_INSERT_LEN);
  insert_sql->q_append(SPIDER_SQL_SQL_IGNORE_STR, SPIDER_SQL_SQL_IGNORE_LEN);
  insert_sql->q_append(SPIDER_SQL_INTO_STR, SPIDER_SQL_INTO_LEN);
  mysql_share->append_table_name(insert_sql, spider->conn_link_idx[link_idx]);
  insert_sql->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  for (field = table->field; *field; field++)
  {
    field_name_length =
      mysql_share->column_name_str[(*field)->field_index].length();
    if (insert_sql->reserve(field_name_length +
      /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    mysql_share->append_column_name(insert_sql, (*field)->field_index);
    insert_sql->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  if (field_name_length)
    insert_sql->length(insert_sql->length() - SPIDER_SQL_COMMA_LEN);
  if (insert_sql->reserve(SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_VALUES_LEN +
    SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  insert_sql->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  insert_sql->q_append(SPIDER_SQL_VALUES_STR, SPIDER_SQL_VALUES_LEN);
  insert_sql->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  for (field = table->field; *field; field++)
  {
    add_value = TRUE;
    if ((*field)->is_null())
    {
      if (insert_sql->reserve(SPIDER_SQL_NULL_LEN + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      insert_sql->q_append(SPIDER_SQL_NULL_STR, SPIDER_SQL_NULL_LEN);
    } else {
      if (spider_db_mbase_utility->append_column_value(spider, insert_sql,
                                                      *field, NULL, false,
                                                      share->access_charset) ||
          insert_sql->reserve(SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    insert_sql->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  if (add_value)
    insert_sql->length(insert_sql->length() - SPIDER_SQL_COMMA_LEN);
  if (insert_sql->reserve(SPIDER_SQL_CLOSE_PAREN_LEN, SPIDER_SQL_COMMA_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  insert_sql->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  if (sql_type == SPIDER_SQL_TYPE_INSERT_SQL)
  {
    exec_insert_sql = insert_sql;
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_update(
  const TABLE *table,
  my_ptrdiff_t ptr_diff
) {
  int error_num;
  spider_string *str = &update_sql;
  DBUG_ENTER("spider_mbase_handler::append_update");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->length() > 0)
  {
    if (str->reserve(SPIDER_SQL_SEMICOLON_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }

  if (
    (error_num = append_update(str, 0)) ||
    (error_num = append_update_set(str)) ||
    (error_num = append_update_where(str, table, ptr_diff))
  )
    DBUG_RETURN(error_num);
  filled_up = (str->length() >= (uint) spider->result_list.bulk_update_size);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_update(
  const TABLE *table,
  my_ptrdiff_t ptr_diff,
  int link_idx
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  spider_string *str = &spider->result_list.update_sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::append_update");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->length() > 0)
  {
    if (str->reserve(SPIDER_SQL_SEMICOLON_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }

  if (
    (error_num = append_update(str, link_idx)) ||
    (error_num = append_update_set(str)) ||
    (error_num = append_update_where(str, table, ptr_diff))
  )
    DBUG_RETURN(error_num);

  if (
    spider->pk_update &&
    share->link_statuses[link_idx] == SPIDER_LINK_STATUS_RECOVERY
  ) {
    if (str->reserve(SPIDER_SQL_SEMICOLON_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
    if ((error_num = append_insert_for_recovery(
      SPIDER_SQL_TYPE_UPDATE_SQL, link_idx)))
      DBUG_RETURN(error_num);
  }

  if (!filled_up)
    filled_up = (str->length() >= (uint) spider->result_list.bulk_update_size);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_delete(
  const TABLE *table,
  my_ptrdiff_t ptr_diff
) {
  int error_num;
  spider_string *str = &update_sql;
  DBUG_ENTER("spider_mbase_handler::append_delete");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->length() > 0)
  {
    if (str->reserve(SPIDER_SQL_SEMICOLON_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }

  if (
    (error_num = append_delete(str)) ||
    (error_num = append_from(str, SPIDER_SQL_TYPE_DELETE_SQL,
      first_link_idx)) ||
    (error_num = append_update_where(str, table, ptr_diff))
  )
    DBUG_RETURN(error_num);
  filled_up = (str->length() >= (uint) spider->result_list.bulk_update_size);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_delete(
  const TABLE *table,
  my_ptrdiff_t ptr_diff,
  int link_idx
) {
  int error_num;
  spider_string *str = &spider->result_list.update_sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::append_delete");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->length() > 0)
  {
    if (str->reserve(SPIDER_SQL_SEMICOLON_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SEMICOLON_STR, SPIDER_SQL_SEMICOLON_LEN);
  }

  if (
    (error_num = append_delete(str)) ||
    (error_num = append_from(str, SPIDER_SQL_TYPE_DELETE_SQL, link_idx)) ||
    (error_num = append_update_where(str, table, ptr_diff))
  )
    DBUG_RETURN(error_num);
  if (!filled_up)
    filled_up = (str->length() >= (uint) spider->result_list.bulk_update_size);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_insert_part()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_insert_part");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = append_insert(&insert_sql, 0);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_insert(
  spider_string *str,
  int link_idx
) {
  DBUG_ENTER("spider_mbase_handler::append_insert");
  direct_insert_kind = SPIDER_SQL_DIRECT_INSERT_KIND_INSERT;
  if (
    (
      spider->wide_handler->write_can_replace ||
      /* for direct_dup_insert without patch for partition */
      spider->wide_handler->sql_command == SQLCOM_REPLACE ||
      spider->wide_handler->sql_command == SQLCOM_REPLACE_SELECT
    ) &&
    spider->direct_dup_insert
  ) {
    direct_insert_kind = SPIDER_SQL_DIRECT_INSERT_KIND_REPLACE;
    if (str->reserve(SPIDER_SQL_REPLACE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_REPLACE_STR, SPIDER_SQL_REPLACE_LEN);
  } else {
    if (str->reserve(SPIDER_SQL_INSERT_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_INSERT_STR, SPIDER_SQL_INSERT_LEN);
  }
  if (spider->wide_handler->low_priority)
  {
    if (str->reserve(SPIDER_SQL_LOW_PRIORITY_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_LOW_PRIORITY_STR, SPIDER_SQL_LOW_PRIORITY_LEN);
  }
  else if (
    spider->wide_handler->lock_type >= TL_WRITE &&
    !spider->wide_handler->write_can_replace &&
    /* for direct_dup_insert without patch for partition */
    spider->wide_handler->sql_command != SQLCOM_REPLACE &&
    spider->wide_handler->sql_command != SQLCOM_REPLACE_SELECT
  ) {
    if (str->reserve(SPIDER_SQL_HIGH_PRIORITY_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_HIGH_PRIORITY_STR, SPIDER_SQL_HIGH_PRIORITY_LEN);
  }
  if (
    spider->wide_handler->ignore_dup_key &&
    spider->direct_dup_insert &&
    !spider->wide_handler->write_can_replace &&
    (!spider->wide_handler->insert_with_update || !dup_update_sql.length()) &&
    /* for direct_dup_insert without patch for partition */
    spider->wide_handler->sql_command != SQLCOM_REPLACE &&
    spider->wide_handler->sql_command != SQLCOM_REPLACE_SELECT
  ) {
    direct_insert_kind = SPIDER_SQL_DIRECT_INSERT_KIND_IGNORE;
    if (str->reserve(SPIDER_SQL_SQL_IGNORE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_IGNORE_STR, SPIDER_SQL_SQL_IGNORE_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_update_part()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_update_part");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = append_update(&update_sql, 0);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_update(
  spider_string *str,
  int link_idx
) {
  DBUG_ENTER("spider_mbase_handler::append_update");
  if (str->reserve(SPIDER_SQL_UPDATE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_UPDATE_STR, SPIDER_SQL_UPDATE_LEN);
  if (spider->wide_handler->low_priority)
  {
    if (str->reserve(SPIDER_SQL_LOW_PRIORITY_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_LOW_PRIORITY_STR, SPIDER_SQL_LOW_PRIORITY_LEN);
  }
  if (
    spider->wide_handler->ignore_dup_key &&
    !spider->wide_handler->insert_with_update
  ) {
    if (str->reserve(SPIDER_SQL_SQL_IGNORE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_IGNORE_STR, SPIDER_SQL_SQL_IGNORE_LEN);
  }
  if (str->reserve(mysql_share->db_nm_max_length +
    SPIDER_SQL_DOT_LEN + mysql_share->table_nm_max_length +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  table_name_pos = str->length();
  append_table_name_with_adjusting(str, link_idx, SPIDER_SQL_TYPE_UPDATE_SQL);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_delete_part()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_delete_part");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = append_delete(&update_sql);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_delete(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_delete");
  if (str->reserve(SPIDER_SQL_DELETE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_DELETE_STR, SPIDER_SQL_DELETE_LEN);
  if (spider->wide_handler->low_priority)
  {
    if (str->reserve(SPIDER_SQL_LOW_PRIORITY_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_LOW_PRIORITY_STR, SPIDER_SQL_LOW_PRIORITY_LEN);
  }
  if (spider->wide_handler->quick_mode)
  {
    if (str->reserve(SPIDER_SQL_SQL_QUICK_MODE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_QUICK_MODE_STR,
      SPIDER_SQL_SQL_QUICK_MODE_LEN);
  }
  if (spider->wide_handler->ignore_dup_key)
  {
    if (str->reserve(SPIDER_SQL_SQL_IGNORE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_IGNORE_STR, SPIDER_SQL_SQL_IGNORE_LEN);
  }
  str->length(str->length() - 1);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_update_set_part()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_update_set_part");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = append_update_set(&update_sql);
  where_pos = update_sql.length();
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_update_set(
  spider_string *str
) {
  uint field_name_length;
  SPIDER_SHARE *share = spider->share;
  TABLE *table = spider->get_table();
  Field **fields;
  DBUG_ENTER("spider_mbase_handler::append_update_set");
  if (str->reserve(SPIDER_SQL_SET_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_SET_STR, SPIDER_SQL_SET_LEN);
  for (fields = table->field; *fields; fields++)
  {
    if (bitmap_is_set(table->write_set, (*fields)->field_index))
    {
      field_name_length =
        mysql_share->column_name_str[(*fields)->field_index].length();
      if ((*fields)->is_null())
      {
        if (str->reserve(field_name_length + /* SPIDER_SQL_NAME_QUOTE_LEN */
          2 + SPIDER_SQL_EQUAL_LEN + SPIDER_SQL_NULL_LEN +
          SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, (*fields)->field_index);
        str->q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN);
        str->q_append(SPIDER_SQL_NULL_STR, SPIDER_SQL_NULL_LEN);
      } else {
        if (str->reserve(field_name_length + /* SPIDER_SQL_NAME_QUOTE_LEN */
          2 + SPIDER_SQL_EQUAL_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, (*fields)->field_index);
        str->q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN);
#ifndef DBUG_OFF
        MY_BITMAP *tmp_map = dbug_tmp_use_all_columns(table, &table->read_set);
#endif
        if (spider_db_mbase_utility->append_column_value(
                spider, str, *fields, NULL, FALSE, share->access_charset) ||
            str->reserve(SPIDER_SQL_COMMA_LEN))
        {
#ifndef DBUG_OFF
          dbug_tmp_restore_column_map(&table->read_set, tmp_map);
#endif
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
#ifndef DBUG_OFF
        dbug_tmp_restore_column_map(&table->read_set, tmp_map);
#endif
      }
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_direct_update_set_part()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_direct_update_set_part");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = append_direct_update_set(&update_sql);
  where_pos = update_sql.length();
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_direct_update_set(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_direct_update_set");
  if (spider->wide_handler->direct_update_fields)
  {
    if (str->reserve(SPIDER_SQL_SET_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SET_STR, SPIDER_SQL_SET_LEN);
    DBUG_RETURN(spider_db_append_update_columns(spider, str, NULL, 0,
      dbton_id, FALSE, NULL));
  }

  DBUG_RETURN(0);
}

int spider_mbase_handler::append_dup_update_pushdown_part(
  const char *alias,
  uint alias_length
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_dup_update_pushdown_part");
  DBUG_PRINT("info",("spider this=%p", this));
  dup_update_sql.length(0);
  error_num = append_update_columns(&dup_update_sql, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_update_columns_part(
  const char *alias,
  uint alias_length
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_update_columns_part");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = append_update_columns(&update_sql, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::check_update_columns_part()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::check_update_columns_part");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = append_update_columns(NULL, NULL, 0);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_update_columns(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_update_columns");
  error_num = spider_db_append_update_columns(spider, str,
    alias, alias_length, dbton_id, FALSE, NULL);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_select_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_select_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_select(str, sql_type);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_select(
  spider_string *str,
  ulong sql_type
) {
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  SPIDER_WIDE_HANDLER *wide_handler = spider->wide_handler;
  DBUG_ENTER("spider_mbase_handler::append_select");
  {
    if (str->reserve(SPIDER_SQL_SELECT_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SELECT_STR, SPIDER_SQL_SELECT_LEN);
    if (result_list->direct_distinct)
    {
      if (str->reserve(SPIDER_SQL_DISTINCT_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_DISTINCT_STR, SPIDER_SQL_DISTINCT_LEN);
    }
    if (wide_handler->external_lock_type != F_WRLCK &&
      wide_handler->lock_mode < 1)
    {
      /* no lock */
      LEX *lex = wide_handler->trx->thd->lex;
      if (
        lex->sql_cache == LEX::SQL_CACHE &&
        (spider->share->query_cache_sync & 1)
      ) {
        if (str->reserve(SPIDER_SQL_SQL_CACHE_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_SQL_CACHE_STR, SPIDER_SQL_SQL_CACHE_LEN);
      } else if (
        lex->sql_cache == LEX::SQL_NO_CACHE &&
        (spider->share->query_cache_sync & 2)
      ) {
        if (str->reserve(SPIDER_SQL_SQL_NO_CACHE_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_SQL_NO_CACHE_STR,
          SPIDER_SQL_SQL_NO_CACHE_LEN);
      } else if (spider->share->query_cache == 1)
      {
        if (str->reserve(SPIDER_SQL_SQL_CACHE_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_SQL_CACHE_STR, SPIDER_SQL_SQL_CACHE_LEN);
      } else if (spider->share->query_cache == 2)
      {
        if (str->reserve(SPIDER_SQL_SQL_NO_CACHE_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_SQL_NO_CACHE_STR,
          SPIDER_SQL_SQL_NO_CACHE_LEN);
      }
    }
    if (wide_handler->high_priority)
    {
      if (str->reserve(SPIDER_SQL_HIGH_PRIORITY_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_HIGH_PRIORITY_STR,
        SPIDER_SQL_HIGH_PRIORITY_LEN);
    }
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_table_select_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_table_select_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_table_select(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_table_select(
  spider_string *str
) {
  st_select_lex *select_lex = NULL;
  bool sgb = (spider->result_list.direct_aggregate &&
    spider_param_strict_group_by(current_thd, (strict_group_by ? 1 : 0)) == 1);
  DBUG_ENTER("spider_mbase_handler::append_table_select");
  if (sgb)
  {
    select_lex = spider_get_select_lex(spider);
    JOIN *join = select_lex->join;
    if (!(*join->sum_funcs) && !select_lex->group_list.elements)
    {
      select_lex = NULL;
    }
  }
  if (select_lex)
  {
    TABLE *table = spider->get_table();
    Field **field;
    int field_length;
    for (field = table->field; *field; field++)
    {
      field_length =
        mysql_share->column_name_str[(*field)->field_index].length();
      if (!spider_db_check_select_colum_in_group(select_lex, *field))
      {
        if (str->reserve(SPIDER_SQL_MIN_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
          field_length + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_MIN_STR, SPIDER_SQL_MIN_LEN);
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
        mysql_share->append_column_name(str, (*field)->field_index);
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
      } else {
        if (str->reserve(field_length + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, (*field)->field_index);
      }
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  } else {
    table_name_pos = str->length() + mysql_share->table_select_pos;
    if (str->append(*(mysql_share->table_select)))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_select_part(
  ulong sql_type,
  uint idx
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_key_select_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_key_select(str, sql_type, idx);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_key_select(
  spider_string *str,
  ulong sql_type,
  uint idx
) {
  st_select_lex *select_lex = NULL;
  bool sgb = (spider->result_list.direct_aggregate &&
    spider_param_strict_group_by(current_thd, (strict_group_by ? 1 : 0)) == 1);
  DBUG_ENTER("spider_mbase_handler::append_key_select");
  if (sgb)
  {
    select_lex = spider_get_select_lex(spider);
    JOIN *join = select_lex->join;
    if (!(*join->sum_funcs) && !select_lex->group_list.elements)
    {
      select_lex = NULL;
    }
  }
  if (select_lex)
  {
    TABLE *table = spider->get_table();
    KEY *key_info = &table->key_info[idx];
    KEY_PART_INFO *key_part;
    Field *field;
    uint part_num;
    int field_length;
    for (key_part = key_info->key_part, part_num = 0;
      part_num < spider_user_defined_key_parts(key_info);
      key_part++, part_num++)
    {
      field = key_part->field;
      field_length = mysql_share->column_name_str[field->field_index].length();
      if (!spider_db_check_select_colum_in_group(select_lex, field))
      {
        if (str->reserve(SPIDER_SQL_MIN_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
          field_length + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_MIN_STR, SPIDER_SQL_MIN_LEN);
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
        mysql_share->append_column_name(str, field->field_index);
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
      } else {
        if (str->reserve(field_length + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, field->field_index);
      }
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
    DBUG_RETURN(append_from(str, sql_type, first_link_idx));
  } else {
    table_name_pos = str->length() + mysql_share->key_select_pos[idx];
    if (str->append(mysql_share->key_select[idx]))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_minimum_select_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_minimum_select_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_minimum_select(str, sql_type);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_minimum_select(
  spider_string *str,
  ulong sql_type
) {
  TABLE *table = spider->get_table();
  Field **field;
  int field_length;
  bool appended = FALSE;
  st_select_lex *select_lex = NULL;
  bool sgb = (spider->result_list.direct_aggregate &&
    spider_param_strict_group_by(current_thd, (strict_group_by ? 1 : 0)) == 1);
  DBUG_ENTER("spider_mbase_handler::append_minimum_select");
  if (sgb)
  {
    select_lex = spider_get_select_lex(spider);
    JOIN *join = select_lex->join;
    if (!(*join->sum_funcs) && !select_lex->group_list.elements)
    {
      select_lex = NULL;
    }
  }
  minimum_select_bitmap_create();
  for (field = table->field; *field; field++)
  {
    if (minimum_select_bit_is_set((*field)->field_index))
    {
/*
      spider_set_bit(minimum_select_bitmap, (*field)->field_index);
*/
      field_length =
        mysql_share->column_name_str[(*field)->field_index].length();
      if (select_lex &&
        !spider_db_check_select_colum_in_group(select_lex, *field))
      {
        if (str->reserve(SPIDER_SQL_MIN_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
          field_length + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_MIN_STR, SPIDER_SQL_MIN_LEN);
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
        mysql_share->append_column_name(str, (*field)->field_index);
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
      } else {
        if (str->reserve(field_length +
          /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, (*field)->field_index);
      }
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      appended = TRUE;
    }
  }
  if (appended)
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  else {
    if (str->reserve(SPIDER_SQL_ONE_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_ONE_STR, SPIDER_SQL_ONE_LEN);
  }
  DBUG_RETURN(append_from(str, sql_type, first_link_idx));
}

int spider_mbase_handler::append_table_select_with_alias(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  TABLE *table = spider->get_table();
  Field **field;
  int field_length;
  st_select_lex *select_lex = NULL;
  bool sgb = (spider->result_list.direct_aggregate &&
    spider_param_strict_group_by(current_thd, (strict_group_by ? 1 : 0)) == 1);
  DBUG_ENTER("spider_mbase_handler::append_table_select_with_alias");
  if (sgb)
  {
    select_lex = spider_get_select_lex(spider);
    JOIN *join = select_lex->join;
    if (!(*join->sum_funcs) && !select_lex->group_list.elements)
    {
      select_lex = NULL;
    }
  }
  for (field = table->field; *field; field++)
  {
    field_length =
      mysql_share->column_name_str[(*field)->field_index].length();
    if (select_lex &&
      !spider_db_check_select_colum_in_group(select_lex, *field))
    {
      if (str->reserve(SPIDER_SQL_MIN_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
        alias_length + field_length + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
        SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_MIN_STR, SPIDER_SQL_MIN_LEN);
      str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
      str->q_append(alias, alias_length);
      mysql_share->append_column_name(str, (*field)->field_index);
      str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
    } else {
      if (str->reserve(alias_length + field_length +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(alias, alias_length);
      mysql_share->append_column_name(str, (*field)->field_index);
    }
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_select_with_alias(
  spider_string *str,
  const KEY *key_info,
  const char *alias,
  uint alias_length
) {
  KEY_PART_INFO *key_part;
  Field *field;
  uint part_num;
  int field_length;
  st_select_lex *select_lex = NULL;
  bool sgb = (spider->result_list.direct_aggregate &&
    spider_param_strict_group_by(current_thd, (strict_group_by ? 1 : 0)) == 1);
  DBUG_ENTER("spider_mbase_handler::append_key_select_with_alias");
  if (sgb)
  {
    select_lex = spider_get_select_lex(spider);
    JOIN *join = select_lex->join;
    if (!(*join->sum_funcs) && !select_lex->group_list.elements)
    {
      select_lex = NULL;
    }
  }
  for (key_part = key_info->key_part, part_num = 0;
    part_num < spider_user_defined_key_parts(key_info); key_part++, part_num++)
  {
    field = key_part->field;
    field_length = mysql_share->column_name_str[field->field_index].length();
    if (select_lex &&
      !spider_db_check_select_colum_in_group(select_lex, field))
    {
      if (str->reserve(SPIDER_SQL_MIN_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
        alias_length + field_length + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
        SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_MIN_STR, SPIDER_SQL_MIN_LEN);
      str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
      str->q_append(alias, alias_length);
      mysql_share->append_column_name(str, field->field_index);
      str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
    } else {
      if (str->reserve(alias_length + field_length +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(alias, alias_length);
      mysql_share->append_column_name(str, field->field_index);
    }
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_minimum_select_with_alias(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  TABLE *table = spider->get_table();
  Field **field;
  int field_length;
  bool appended = FALSE;
  st_select_lex *select_lex = NULL;
  bool sgb = (spider->result_list.direct_aggregate &&
    spider_param_strict_group_by(current_thd, (strict_group_by ? 1 : 0)) == 1);
  DBUG_ENTER("spider_mbase_handler::append_minimum_select_with_alias");
  if (sgb)
  {
    select_lex = spider_get_select_lex(spider);
    JOIN *join = select_lex->join;
    if (!(*join->sum_funcs) && !select_lex->group_list.elements)
    {
      select_lex = NULL;
    }
  }
  minimum_select_bitmap_create();
  for (field = table->field; *field; field++)
  {
    if (minimum_select_bit_is_set((*field)->field_index))
    {
/*
      spider_set_bit(minimum_select_bitmap, (*field)->field_index);
*/
      field_length =
        mysql_share->column_name_str[(*field)->field_index].length();
      if (select_lex &&
        !spider_db_check_select_colum_in_group(select_lex, *field))
      {
        if (str->reserve(SPIDER_SQL_MIN_LEN + SPIDER_SQL_OPEN_PAREN_LEN +
          alias_length + field_length + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_MIN_STR, SPIDER_SQL_MIN_LEN);
        str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
        str->q_append(alias, alias_length);
        mysql_share->append_column_name(str, (*field)->field_index);
        str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
      } else {
        if (str->reserve(alias_length + field_length +
          /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(alias, alias_length);
        mysql_share->append_column_name(str, (*field)->field_index);
      }
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      appended = TRUE;
    }
  }
  if (appended)
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  else {
    if (str->reserve(SPIDER_SQL_ONE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_ONE_STR, SPIDER_SQL_ONE_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_select_columns_with_alias(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  int error_num;
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  DBUG_ENTER("spider_mbase_handler::append_select_columns_with_alias");
  if (
    result_list->direct_aggregate &&
    (error_num = append_sum_select(str, alias, alias_length))
  )
    DBUG_RETURN(error_num);
  if ((error_num = append_match_select(str, alias, alias_length)))
    DBUG_RETURN(error_num);
  if (!spider->select_column_mode)
  {
    if (result_list->keyread)
      DBUG_RETURN(append_key_select_with_alias(
        str, result_list->key_info, alias, alias_length));
    else
      DBUG_RETURN(append_table_select_with_alias(
        str, alias, alias_length));
  }
  DBUG_RETURN(append_minimum_select_with_alias(str, alias, alias_length));
}

int spider_mbase_handler::append_hint_after_table_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_hint_after_table_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_hint_after_table(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_hint_after_table(
  spider_string *str
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_hint_after_table");
  DBUG_PRINT("info",("spider this=%p", this));
  if (
    mysql_share->key_hint &&
    (error_num = spider_db_append_hint_after_table(spider,
      str, &mysql_share->key_hint[spider->active_index]))
  )
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  DBUG_RETURN(0);
}

void spider_mbase_handler::set_where_pos(
  ulong sql_type
) {
  DBUG_ENTER("spider_mbase_handler::set_where_pos");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      where_pos = sql.length();
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      where_pos = update_sql.length();
      break;
    default:
      break;
  }
  DBUG_VOID_RETURN;
}

void spider_mbase_handler::set_where_to_pos(
  ulong sql_type
) {
  DBUG_ENTER("spider_mbase_handler::set_where_to_pos");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      sql.length(where_pos);
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      update_sql.length(where_pos);
      break;
    default:
      break;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_handler::check_item_type(
  Item *item
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::check_item_type");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = spider_db_print_item_type(item, NULL, spider, NULL, NULL, 0,
    dbton_id, FALSE, NULL);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_values_connector_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_values_connector_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_values_connector(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_values_connector(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_values_connector");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN +
    SPIDER_SQL_COMMA_LEN + SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_values_terminator_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_values_terminator_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_values_terminator(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_values_terminator(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_values_terminator");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(str->length() -
    SPIDER_SQL_COMMA_LEN - SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_union_table_connector_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_union_table_connector_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_union_table_connector(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_union_table_connector(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_union_table_connector");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve((SPIDER_SQL_SPACE_LEN * 2) + SPIDER_SQL_UNION_ALL_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
  str->q_append(SPIDER_SQL_UNION_ALL_STR, SPIDER_SQL_UNION_ALL_LEN);
  str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_union_table_terminator_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_union_table_terminator_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_union_table_terminator(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_union_table_terminator(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_union_table_terminator");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(str->length() -
    ((SPIDER_SQL_SPACE_LEN * 2) + SPIDER_SQL_UNION_ALL_LEN));
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  table_name_pos = str->length() + SPIDER_SQL_SPACE_LEN + SPIDER_SQL_A_LEN +
    SPIDER_SQL_COMMA_LEN;
  if (str->reserve(tmp_sql.length() - SPIDER_SQL_FROM_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(tmp_sql.ptr() + SPIDER_SQL_FROM_LEN,
    tmp_sql.length() - SPIDER_SQL_FROM_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_column_values_part(
  const key_range *start_key,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_key_column_values_part");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_key_column_values(str, start_key);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_key_column_values(
  spider_string *str,
  const key_range *start_key
) {
  int error_num;
  const uchar *ptr;
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  SPIDER_SHARE *share = spider->share;
  KEY *key_info = result_list->key_info;
  uint length;
  uint store_length;
  key_part_map full_key_part_map =
    make_prev_keypart_map(spider_user_defined_key_parts(key_info));
  key_part_map start_key_part_map;
  KEY_PART_INFO *key_part;
  Field *field;
  DBUG_ENTER("spider_mbase_handler::append_key_column_values");
  start_key_part_map = start_key->keypart_map & full_key_part_map;
  DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u",
    spider_user_defined_key_parts(key_info)));
  DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map));
  DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map));

  if (!start_key_part_map)
    DBUG_RETURN(0);

  for (
    key_part = key_info->key_part,
    length = 0;
    start_key_part_map;
    start_key_part_map >>= 1,
    key_part++,
    length += store_length
  ) {
    store_length = key_part->store_length;
    ptr = start_key->key + length;
    field = key_part->field;
    if ((error_num = spider_db_append_null_value(str, key_part, &ptr)))
    {
      if (error_num > 0)
        DBUG_RETURN(error_num);
    } else {
      if (spider_db_mbase_utility->append_column_value(
              spider, str, field, ptr, FALSE, share->access_charset))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }

    if (str->reserve(SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_column_values_with_name_part(
  const key_range *start_key,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_key_column_values_with_name_part");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_key_column_values_with_name(str, start_key);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_key_column_values_with_name(
  spider_string *str,
  const key_range *start_key
) {
  int error_num;
  const uchar *ptr;
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  SPIDER_SHARE *share = spider->share;
  KEY *key_info = result_list->key_info;
  uint length;
  uint key_name_length, key_count;
  uint store_length;
  key_part_map full_key_part_map =
    make_prev_keypart_map(spider_user_defined_key_parts(key_info));
  key_part_map start_key_part_map;
  KEY_PART_INFO *key_part;
  Field *field;
  char tmp_buf[MAX_FIELD_WIDTH];
  DBUG_ENTER("spider_mbase_handler::append_key_column_values_with_name");
  start_key_part_map = start_key->keypart_map & full_key_part_map;
  DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u",
    spider_user_defined_key_parts(key_info)));
  DBUG_PRINT("info", ("spider full_key_part_map=%lu", full_key_part_map));
  DBUG_PRINT("info", ("spider start_key_part_map=%lu", start_key_part_map));

  if (!start_key_part_map)
    DBUG_RETURN(0);

  for (
    key_part = key_info->key_part,
    length = 0,
    key_count = 0;
    start_key_part_map;
    start_key_part_map >>= 1,
    key_part++,
    length += store_length,
    key_count++
  ) {
    store_length = key_part->store_length;
    ptr = start_key->key + length;
    field = key_part->field;
    if ((error_num = spider_db_append_null_value(str, key_part, &ptr)))
    {
      if (error_num > 0)
        DBUG_RETURN(error_num);
    } else {
      if (spider_db_mbase_utility->append_column_value(
              spider, str, field, ptr, FALSE, share->access_charset))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }

    key_name_length = my_sprintf(tmp_buf, (tmp_buf, "c%u", key_count));
    if (str->reserve(SPIDER_SQL_SPACE_LEN + key_name_length +
      SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
    str->q_append(tmp_buf, key_name_length);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_where_part(
  const key_range *start_key,
  const key_range *end_key,
  ulong sql_type
) {
  int error_num;
  spider_string *str, *str_part = NULL, *str_part2 = NULL;
  bool set_order;
  DBUG_ENTER("spider_mbase_handler::append_key_where_part");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      set_order = FALSE;
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      set_order = FALSE;
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      set_order = FALSE;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_key_where(str, str_part, str_part2, start_key, end_key,
    sql_type, set_order);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_key_where(
  spider_string *str,
  spider_string *str_part,
  spider_string *str_part2,
  const key_range *start_key,
  const key_range *end_key,
  ulong sql_type,
  bool set_order
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_key_where");
  error_num = spider_db_append_key_where_internal(str, str_part, str_part2,
    start_key, end_key, spider, set_order, sql_type,
    dbton_id);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_is_null_part(
  ulong sql_type,
  KEY_PART_INFO *key_part,
  const key_range *key,
  const uchar **ptr,
  bool key_eq,
  bool tgt_final
) {
  int error_num;
  spider_string *str, *str_part = NULL, *str_part2 = NULL;
  DBUG_ENTER("spider_mbase_handler::append_is_null_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_is_null(sql_type, str, str_part, str_part2,
    key_part, key, ptr, key_eq, tgt_final);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_is_null(
  ulong sql_type,
  spider_string *str,
  spider_string *str_part,
  spider_string *str_part2,
  KEY_PART_INFO *key_part,
  const key_range *key,
  const uchar **ptr,
  bool key_eq,
  bool tgt_final
) {
  DBUG_ENTER("spider_mbase_handler::append_is_null");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider key_eq=%s", key_eq ? "TRUE" : "FALSE"));
  if (key_part->null_bit)
  {
    if (*(*ptr)++)
    {
      if (
        key_eq ||
        key->flag == HA_READ_KEY_EXACT ||
        key->flag == HA_READ_KEY_OR_NEXT
      ) {
        if (str->reserve(SPIDER_SQL_IS_NULL_LEN +
          /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          mysql_share->column_name_str[key_part->field->field_index].length()))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, key_part->field->field_index);
        str->q_append(SPIDER_SQL_IS_NULL_STR, SPIDER_SQL_IS_NULL_LEN);
      } else {
        if (str->reserve(SPIDER_SQL_IS_NOT_NULL_LEN +
          /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          mysql_share->column_name_str[key_part->field->field_index].length()))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, key_part->field->field_index);
        str->q_append(SPIDER_SQL_IS_NOT_NULL_STR, SPIDER_SQL_IS_NOT_NULL_LEN);
      }
      DBUG_RETURN(-1);
    }
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_where_terminator_part(
  ulong sql_type,
  bool set_order,
  int key_count
) {
  int error_num;
  spider_string *str, *str_part = NULL, *str_part2 = NULL;
  DBUG_ENTER("spider_mbase_handler::append_where_terminator_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_where_terminator(sql_type, str, str_part, str_part2,
    set_order, key_count);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_where_terminator(
  ulong sql_type,
  spider_string *str,
  spider_string *str_part,
  spider_string *str_part2,
  bool set_order,
  int key_count
) {
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  DBUG_ENTER("spider_mbase_handler::append_where_terminator");
  DBUG_PRINT("info", ("spider this=%p", this));

  str->length(str->length() - SPIDER_SQL_AND_LEN);
  if (!set_order)
    result_list->key_order= key_count;
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_match_where_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_match_where_part");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_ASSERT(0);
      DBUG_RETURN(0);
  }
  error_num = append_match_where(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_match_where(
  spider_string *str
) {
  int error_num;
  bool first = TRUE;
  st_spider_ft_info *ft_info = spider->ft_first;
  DBUG_ENTER("spider_mbase_handler::append_match_where");
  if (spider->ft_current)
  {
    while (TRUE)
    {
      if (ft_info->used_in_where)
      {
        if (first)
        {
          if (str->reserve(SPIDER_SQL_WHERE_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_WHERE_STR, SPIDER_SQL_WHERE_LEN);
          first = FALSE;
        }
        if ((error_num = append_match_against(str, ft_info, NULL, 0)))
          DBUG_RETURN(error_num);
        if (str->reserve(SPIDER_SQL_AND_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
      }

      if (ft_info == spider->ft_current)
        break;
      ft_info = ft_info->next;
    }
    if (!first)
      str->length(str->length() - SPIDER_SQL_AND_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_update_where(
  spider_string *str,
  const TABLE *table,
  my_ptrdiff_t ptr_diff
) {
  uint field_name_length;
  Field **field;
  THD *thd = spider->wide_handler->trx->thd;
  SPIDER_SHARE *share = spider->share;
  bool no_pk = (table->s->primary_key == MAX_KEY);
  DBUG_ENTER("spider_mbase_handler::append_update_where");
  DBUG_PRINT("info", ("spider table->s->primary_key=%s",
    table->s->primary_key != MAX_KEY ? "TRUE" : "FALSE"));
  uint str_len_bakup = str->length();
  if (str->reserve(SPIDER_SQL_WHERE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_WHERE_STR, SPIDER_SQL_WHERE_LEN);

  if (
    no_pk ||
    spider_param_use_cond_other_than_pk_for_update(thd)
  ) {
    for (field = table->field; *field; field++)
    {
      if (
        no_pk ||
        bitmap_is_set(table->read_set, (*field)->field_index)
      ) {
        field_name_length =
          mysql_share->column_name_str[(*field)->field_index].length();
        if ((*field)->is_null(ptr_diff))
        {
          if (str->reserve(field_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
            SPIDER_SQL_IS_NULL_LEN + SPIDER_SQL_AND_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          mysql_share->append_column_name(str, (*field)->field_index);
          str->q_append(SPIDER_SQL_IS_NULL_STR, SPIDER_SQL_IS_NULL_LEN);
        } else {
          if (str->reserve(field_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
            SPIDER_SQL_EQUAL_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          mysql_share->append_column_name(str, (*field)->field_index);
          str->q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN);
          (*field)->move_field_offset(ptr_diff);
          if (spider_db_mbase_utility->append_column_value(
                  spider, str, *field, NULL, FALSE, share->access_charset) ||
              str->reserve(SPIDER_SQL_AND_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          (*field)->move_field_offset(-ptr_diff);
        }
        str->q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
      }
    }
  } else {
    KEY *key_info = &table->key_info[table->s->primary_key];
    KEY_PART_INFO *key_part;
    uint part_num;
    for (
      key_part = key_info->key_part, part_num = 0;
      part_num < spider_user_defined_key_parts(key_info);
      key_part++, part_num++
    ) {
      field = &key_part->field;
      field_name_length =
        mysql_share->column_name_str[(*field)->field_index].length();
      if ((*field)->is_null(ptr_diff))
      {
        if (str->reserve(field_name_length +
          /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          SPIDER_SQL_IS_NULL_LEN + SPIDER_SQL_AND_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, (*field)->field_index);
        str->q_append(SPIDER_SQL_IS_NULL_STR, SPIDER_SQL_IS_NULL_LEN);
      } else {
        if (str->reserve(field_name_length +
          /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
          SPIDER_SQL_EQUAL_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        mysql_share->append_column_name(str, (*field)->field_index);
        str->q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN);
        (*field)->move_field_offset(ptr_diff);
        if (spider_db_mbase_utility->append_column_value(
                spider, str, *field, NULL, FALSE, share->access_charset) ||
            str->reserve(SPIDER_SQL_AND_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        (*field)->move_field_offset(-ptr_diff);
      }
      str->q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
    }
  }
  if (str->length() == str_len_bakup + SPIDER_SQL_WHERE_LEN)
  {
    /* no condition */
    str->length(str_len_bakup);
  } else {
    str->length(str->length() - SPIDER_SQL_AND_LEN);
  }
  if (str->reserve(SPIDER_SQL_LIMIT1_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_LIMIT1_STR, SPIDER_SQL_LIMIT1_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_condition_part(
  const char *alias,
  uint alias_length,
  ulong sql_type,
  bool test_flg
) {
  int error_num;
  spider_string *str;
  bool start_where = FALSE;
  DBUG_ENTER("spider_mbase_handler::append_condition_part");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      if (test_flg)
      {
        str = NULL;
      } else {
        str = &sql;
        start_where = ((int) str->length() == where_pos);
      }
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      if (test_flg)
      {
        str = NULL;
      } else {
        str = &tmp_sql;
        start_where = ((int) str->length() == where_pos);
      }
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      if (test_flg)
      {
        str = NULL;
      } else {
        str = &update_sql;
        start_where = ((int) str->length() == where_pos);
      }
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_condition(str, alias, alias_length, start_where,
    sql_type);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_condition(
  spider_string *str,
  const char *alias,
  uint alias_length,
  bool start_where,
  ulong sql_type
) {
  int error_num, restart_pos = 0, start_where_pos;
  SPIDER_CONDITION *tmp_cond = spider->wide_handler->condition;
  DBUG_ENTER("spider_mbase_handler::append_condition");
  if (str && start_where)
  {
    start_where_pos = str->length();
  } else {
    start_where_pos = 0;
  }

  if (spider->is_clone && !tmp_cond)
  {
    tmp_cond = spider->pt_clone_source_handler->wide_handler->condition;
  }

  while (tmp_cond)
  {
    if (str)
    {
      restart_pos = str->length();
      if (start_where)
      {
        if (str->reserve(SPIDER_SQL_WHERE_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_WHERE_STR, SPIDER_SQL_WHERE_LEN);
        start_where = FALSE;
      } else {
        if (str->reserve(SPIDER_SQL_AND_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
      }
    }
    if ((error_num = spider_db_print_item_type(
      (Item *) tmp_cond->cond, NULL, spider, str, alias, alias_length,
      dbton_id, FALSE, NULL)))
    {
      if (str && error_num == ER_SPIDER_COND_SKIP_NUM)
      {
        DBUG_PRINT("info",("spider COND skip"));
        str->length(restart_pos);
        start_where = (restart_pos == start_where_pos);
      } else
        DBUG_RETURN(error_num);
    }
    tmp_cond = tmp_cond->next;
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_match_against_part(
  ulong sql_type,
  st_spider_ft_info *ft_info,
  const char *alias,
  uint alias_length
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_match_against_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_match_against(str, ft_info, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_match_against(
  spider_string *str,
  st_spider_ft_info  *ft_info,
  const char *alias,
  uint alias_length
) {
  SPIDER_SHARE *share = spider->share;
  TABLE *table = spider->get_table();
  String *ft_init_key;
  KEY *key_info;
  uint key_name_length;
  int key_count;
  KEY_PART_INFO *key_part;
  Field *field;
  DBUG_ENTER("spider_mbase_handler::append_match_against");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_MATCH_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_MATCH_STR, SPIDER_SQL_MATCH_LEN);

  ft_init_key = ft_info->key;
  key_info = &table->key_info[ft_info->inx];
  DBUG_PRINT("info", ("spider spider_user_defined_key_parts=%u",
    spider_user_defined_key_parts(key_info)));

  for (
    key_part = key_info->key_part,
    key_count = 0;
    key_count < (int) spider_user_defined_key_parts(key_info);
    key_part++,
    key_count++
  ) {
    field = key_part->field;
    key_name_length =
      mysql_share->column_name_str[field->field_index].length();
    if (alias_length)
    {
      if (str->reserve(alias_length + key_name_length +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(alias, alias_length);
    } else {
      if (str->reserve(key_name_length +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    mysql_share->append_column_name(str, field->field_index);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  if (str->reserve(SPIDER_SQL_AGAINST_LEN + SPIDER_SQL_VALUE_QUOTE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_AGAINST_STR, SPIDER_SQL_AGAINST_LEN);
  str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);

  char buf[MAX_FIELD_WIDTH];
  spider_string tmp_str(buf, MAX_FIELD_WIDTH, share->access_charset);
  tmp_str.init_calc_mem(SPD_MID_MBASE_HANDLER_APPEND_MATCH_AGAINST_1);
  tmp_str.length(0);
  if (
    tmp_str.append(ft_init_key->ptr(), ft_init_key->length(),
      ft_init_key->charset()) ||
    str->reserve(tmp_str.length() * 2) ||
    spider_db_mbase_utility->append_escaped_util(str, tmp_str.get_str())
  )
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->mem_calc();

  if (str->reserve(
    SPIDER_SQL_VALUE_QUOTE_LEN + SPIDER_SQL_CLOSE_PAREN_LEN +
    ((ft_info->flags & FT_BOOL) ? SPIDER_SQL_IN_BOOLEAN_MODE_LEN : 0) +
    ((ft_info->flags & FT_EXPAND) ?
      SPIDER_SQL_WITH_QUERY_EXPANSION_LEN : 0)
  ))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  if (ft_info->flags & FT_BOOL)
    str->q_append(SPIDER_SQL_IN_BOOLEAN_MODE_STR,
      SPIDER_SQL_IN_BOOLEAN_MODE_LEN);
  if (ft_info->flags & FT_EXPAND)
    str->q_append(SPIDER_SQL_WITH_QUERY_EXPANSION_STR,
      SPIDER_SQL_WITH_QUERY_EXPANSION_LEN);
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_match_select_part(
  ulong sql_type,
  const char *alias,
  uint alias_length
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_match_select_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_match_select(str, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_match_select(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_match_select");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider->ft_current)
  {
    st_spider_ft_info *ft_info = spider->ft_first;
    while (TRUE)
    {
      if ((error_num = append_match_against(str, ft_info,
        alias, alias_length)))
        DBUG_RETURN(error_num);
      if (str->reserve(SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      if (ft_info == spider->ft_current)
        break;
      ft_info = ft_info->next;
    }
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_sum_select_part(
  ulong sql_type,
  const char *alias,
  uint alias_length
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_sum_select_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_sum_select(str, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_sum_select(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  int error_num;
  st_select_lex *select_lex;
  DBUG_ENTER("spider_mbase_handler::append_sum_select");
  DBUG_PRINT("info",("spider this=%p", this));
  select_lex = spider_get_select_lex(spider);
  JOIN *join = select_lex->join;
  Item_sum **item_sum_ptr;
  for (item_sum_ptr = join->sum_funcs; *item_sum_ptr; ++item_sum_ptr)
  {
    if ((error_num = spider_db_mbase_utility->open_item_sum_func(*item_sum_ptr,
      spider, str, alias, alias_length, FALSE, NULL)))
    {
      DBUG_RETURN(error_num);
    }
    if (str->reserve(SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  DBUG_RETURN(0);
}

void spider_mbase_handler::set_order_pos(
  ulong sql_type
) {
  DBUG_ENTER("spider_mbase_handler::set_order_pos");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      order_pos = sql.length();
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      order_pos = update_sql.length();
      break;
    default:
      DBUG_ASSERT(0);
      break;
  }
  DBUG_VOID_RETURN;
}

void spider_mbase_handler::set_order_to_pos(
  ulong sql_type
) {
  DBUG_ENTER("spider_mbase_handler::set_order_to_pos");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      sql.length(order_pos);
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      update_sql.length(order_pos);
      break;
    default:
      DBUG_ASSERT(0);
      break;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_handler::append_group_by_part(
  const char *alias,
  uint alias_length,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_group_by_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_group_by(str, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_group_by(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  int error_num;
  st_select_lex *select_lex;
  DBUG_ENTER("spider_mbase_handler::append_group_by");
  DBUG_PRINT("info",("spider this=%p", this));
  select_lex = spider_get_select_lex(spider);
  ORDER *group = (ORDER *) select_lex->group_list.first;
  if (group)
  {
    if (str->reserve(SPIDER_SQL_GROUP_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_GROUP_STR, SPIDER_SQL_GROUP_LEN);
    for (; group; group = group->next)
    {
      if ((error_num = spider_db_print_item_type((*group->item), NULL, spider,
        str, alias, alias_length, dbton_id, FALSE, NULL)))
      {
        DBUG_RETURN(error_num);
      }
      if (str->reserve(SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_order_for_merge_with_alias_part(
  const char *alias,
  uint alias_length,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_key_order_for_merge_with_alias_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_key_order_for_merge_with_alias(str, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_key_order_for_merge_with_alias(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  /* sort for index merge */
  TABLE *table = spider->get_table();
  int length;
  Field *field;
  uint key_name_length;
  DBUG_ENTER("spider_mbase_handler::append_key_order_for_merge_with_alias");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider->result_list.direct_aggregate)
  {
    int error_num;
    if ((error_num = append_group_by(str, alias, alias_length)))
      DBUG_RETURN(error_num);
  }
  if (table->s->primary_key < MAX_KEY)
  {
    /* sort by primary key */
    KEY *key_info = &table->key_info[table->s->primary_key];
    KEY_PART_INFO *key_part;
    for (
      key_part = key_info->key_part,
      length = 1;
      length <= (int) spider_user_defined_key_parts(key_info);
      key_part++,
      length++
    ) {
      field = key_part->field;
      key_name_length =
        mysql_share->column_name_str[field->field_index].length();
      if (length == 1)
      {
        if (str->reserve(SPIDER_SQL_ORDER_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
      }
      if (str->reserve(alias_length + key_name_length +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(alias, alias_length);
      mysql_share->append_column_name(str, field->field_index);
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
    if (length > 1)
    {
      str->length(str->length() - SPIDER_SQL_COMMA_LEN);
    }
  } else {
    /* sort by all columns */
    Field **fieldp;
    for (
      fieldp = table->field, length = 1;
      *fieldp;
      fieldp++, length++
    ) {
      key_name_length =
        mysql_share->column_name_str[(*fieldp)->field_index].length();
      if (length == 1)
      {
        if (str->reserve(SPIDER_SQL_ORDER_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
      }
      if (str->reserve(alias_length + key_name_length +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(alias, alias_length);
      mysql_share->append_column_name(str, (*fieldp)->field_index);
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
    if (length > 1)
    {
      str->length(str->length() - SPIDER_SQL_COMMA_LEN);
    }
  }
  limit_pos = str->length();
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_order_for_direct_order_limit_with_alias_part(
  const char *alias,
  uint alias_length,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_key_order_for_direct_order_limit_with_alias_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_key_order_for_direct_order_limit_with_alias(
    str, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_key_order_for_direct_order_limit_with_alias(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  int error_num;
  ORDER *order;
  st_select_lex *select_lex;
  longlong select_limit;
  longlong offset_limit;
  DBUG_ENTER("spider_mbase_handler::append_key_order_for_direct_order_limit_with_alias");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider->result_list.direct_aggregate)
  {
    if ((error_num = append_group_by(str, alias, alias_length)))
      DBUG_RETURN(error_num);
  }
  spider_get_select_limit(spider, &select_lex, &select_limit,
    &offset_limit);
  if (select_lex->order_list.first)
  {
    if (str->reserve(SPIDER_SQL_ORDER_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
    for (order = (ORDER *) select_lex->order_list.first; order;
      order = order->next)
    {
      if ((error_num =
        spider_db_print_item_type((*order->item), NULL, spider, str, alias,
          alias_length, dbton_id, FALSE, NULL)))
      {
        DBUG_PRINT("info",("spider error=%d", error_num));
        DBUG_RETURN(error_num);
      }
      if (SPIDER_order_direction_is_asc(order))
      {
        if (str->reserve(SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      } else {
        if (str->reserve(SPIDER_SQL_DESC_LEN + SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_DESC_STR, SPIDER_SQL_DESC_LEN);
        str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      }
    }
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  }
  limit_pos = str->length();
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_order_with_alias_part(
  const char *alias,
  uint alias_length,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_key_order_with_alias_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_key_order_with_alias(str, alias, alias_length);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_key_order_for_handler(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  DBUG_ENTER("spider_mbase_handler::append_key_order_for_handler");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider ha_next_pos=%d", ha_next_pos));
  DBUG_PRINT("info",("spider ha_where_pos=%d", ha_where_pos));
  str->q_append(alias, alias_length);
  memset((char *) str->ptr() + str->length(), ' ',
    ha_where_pos - ha_next_pos - alias_length);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_key_order_with_alias(
  spider_string *str,
  const char *alias,
  uint alias_length
) {
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  KEY *key_info = result_list->key_info;
  int length;
  KEY_PART_INFO *key_part;
  Field *field;
  uint key_name_length;
  DBUG_ENTER("spider_mbase_handler::append_key_order_with_alias");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider->result_list.direct_aggregate)
  {
    int error_num;
    if ((error_num = append_group_by(str, alias, alias_length)))
      DBUG_RETURN(error_num);
  }
  if (result_list->sorted == TRUE)
  {
    if (result_list->desc_flg == TRUE)
    {
      for (
        key_part = key_info->key_part + result_list->key_order,
        length = 1;
        length + result_list->key_order <
          (int) spider_user_defined_key_parts(key_info) &&
        length < result_list->max_order;
        key_part++,
        length++
      ) {
        field = key_part->field;
        key_name_length =
          mysql_share->column_name_str[field->field_index].length();
        if (length == 1)
        {
          if (str->reserve(SPIDER_SQL_ORDER_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
        }
        if (key_part->key_part_flag & HA_REVERSE_SORT)
        {
          if (str->reserve(alias_length + key_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(alias, alias_length);
          mysql_share->append_column_name(str, field->field_index);
          str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
        } else {
          if (str->reserve(alias_length + key_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
            SPIDER_SQL_DESC_LEN + SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(alias, alias_length);
          mysql_share->append_column_name(str, field->field_index);
          str->q_append(SPIDER_SQL_DESC_STR, SPIDER_SQL_DESC_LEN);
          str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
        }
      }
      if (
        length + result_list->key_order <=
          (int) spider_user_defined_key_parts(key_info) &&
        length <= result_list->max_order
      ) {
        field = key_part->field;
        key_name_length =
          mysql_share->column_name_str[field->field_index].length();
        if (length == 1)
        {
          if (str->reserve(SPIDER_SQL_ORDER_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
        }
        if (key_part->key_part_flag & HA_REVERSE_SORT)
        {
          if (str->reserve(alias_length + key_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(alias, alias_length);
          mysql_share->append_column_name(str, field->field_index);
        } else {
          if (str->reserve(alias_length + key_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_DESC_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(alias, alias_length);
          mysql_share->append_column_name(str, field->field_index);
          str->q_append(SPIDER_SQL_DESC_STR, SPIDER_SQL_DESC_LEN);
        }
      }
    } else {
      for (
        key_part = key_info->key_part + result_list->key_order,
        length = 1;
        length + result_list->key_order <
          (int) spider_user_defined_key_parts(key_info) &&
        length < result_list->max_order;
        key_part++,
        length++
      ) {
        field = key_part->field;
        key_name_length =
          mysql_share->column_name_str[field->field_index].length();
        if (length == 1)
        {
          if (str->reserve(SPIDER_SQL_ORDER_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
        }
        if (key_part->key_part_flag & HA_REVERSE_SORT)
        {
          if (str->reserve(alias_length + key_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
            SPIDER_SQL_DESC_LEN + SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(alias, alias_length);
          mysql_share->append_column_name(str, field->field_index);
          str->q_append(SPIDER_SQL_DESC_STR, SPIDER_SQL_DESC_LEN);
          str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
        } else {
          if (str->reserve(alias_length + key_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(alias, alias_length);
          mysql_share->append_column_name(str, field->field_index);
          str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
        }
      }
      if (
        length + result_list->key_order <=
          (int) spider_user_defined_key_parts(key_info) &&
        length <= result_list->max_order
      ) {
        field = key_part->field;
        key_name_length =
          mysql_share->column_name_str[field->field_index].length();
        if (length == 1)
        {
          if (str->reserve(SPIDER_SQL_ORDER_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
        }
        if (key_part->key_part_flag & HA_REVERSE_SORT)
        {
          if (str->reserve(alias_length + key_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_DESC_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(alias, alias_length);
          mysql_share->append_column_name(str, field->field_index);
          str->q_append(SPIDER_SQL_DESC_STR, SPIDER_SQL_DESC_LEN);
        } else {
          if (str->reserve(alias_length + key_name_length +
            /* SPIDER_SQL_NAME_QUOTE_LEN */ 2))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          str->q_append(alias, alias_length);
          mysql_share->append_column_name(str, field->field_index);
        }
      }
    }
  }
  limit_pos = str->length();
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_limit_part(
  longlong offset,
  longlong limit,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_limit_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      limit_pos = str->length();
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      limit_pos = str->length();
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      limit_pos = str->length();
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_limit(str, offset, limit);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::reappend_limit_part(
  longlong offset,
  longlong limit,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::reappend_limit_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      str->length(limit_pos);
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      str->length(limit_pos);
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      str->length(limit_pos);
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_limit(str, offset, limit);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_limit(
  spider_string *str,
  longlong offset,
  longlong limit
) {
  char buf[SPIDER_LONGLONG_LEN + 1];
  uint32 length;
  DBUG_ENTER("spider_mbase_handler::append_limit");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info", ("spider offset=%lld", offset));
  DBUG_PRINT("info", ("spider limit=%lld", limit));
  if (offset || limit < 9223372036854775807LL)
  {
    if (str->reserve(SPIDER_SQL_LIMIT_LEN + SPIDER_SQL_COMMA_LEN +
      ((SPIDER_LONGLONG_LEN) * 2)))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_LIMIT_STR, SPIDER_SQL_LIMIT_LEN);
    if (offset)
    {
      length = (uint32) (my_charset_bin.longlong10_to_str)(
        buf, SPIDER_LONGLONG_LEN + 1, -10, offset);
      str->q_append(buf, length);
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
    length = (uint32) (my_charset_bin.longlong10_to_str)(
      buf, SPIDER_LONGLONG_LEN + 1, -10, limit);
    str->q_append(buf, length);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_select_lock_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_select_lock_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_select_lock(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_select_lock(
  spider_string *str
) {
  int lock_mode = spider_conn_lock_mode(spider);
  DBUG_ENTER("spider_mbase_handler::append_select_lock");
  DBUG_PRINT("info",("spider this=%p", this));
  if (lock_mode == SPIDER_LOCK_MODE_EXCLUSIVE)
  {
    if (str->reserve(SPIDER_SQL_FOR_UPDATE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_FOR_UPDATE_STR, SPIDER_SQL_FOR_UPDATE_LEN);
  } else if (lock_mode == SPIDER_LOCK_MODE_SHARED)
  {
    if (str->reserve(SPIDER_SQL_SHARED_LOCK_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SHARED_LOCK_STR, SPIDER_SQL_SHARED_LOCK_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_union_all_start_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_union_all_start_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_union_all_start(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_union_all_start(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_union_all_start");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_union_all_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_union_all_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_union_all(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_union_all(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_union_all");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_UNION_ALL_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_UNION_ALL_STR, SPIDER_SQL_UNION_ALL_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_union_all_end_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_union_all_end_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_union_all_end(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_union_all_end(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_union_all_end");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(str->length() -
    SPIDER_SQL_UNION_ALL_LEN + SPIDER_SQL_CLOSE_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_multi_range_cnt_part(
  ulong sql_type,
  uint multi_range_cnt,
  bool with_comma
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_multi_range_cnt_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_multi_range_cnt(str, multi_range_cnt, with_comma);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_multi_range_cnt(
  spider_string *str,
  uint multi_range_cnt,
  bool with_comma
) {
  int range_cnt_length;
  char range_cnt_str[SPIDER_SQL_INT_LEN];
  DBUG_ENTER("spider_mbase_handler::append_multi_range_cnt");
  DBUG_PRINT("info",("spider this=%p", this));
  range_cnt_length = my_sprintf(range_cnt_str, (range_cnt_str, "%u",
    multi_range_cnt));
  if (with_comma)
  {
    if (str->reserve(range_cnt_length + SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(range_cnt_str, range_cnt_length);
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  } else {
    if (str->reserve(range_cnt_length))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(range_cnt_str, range_cnt_length);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_multi_range_cnt_with_name_part(
  ulong sql_type,
  uint multi_range_cnt
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_multi_range_cnt_with_name_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      str = &tmp_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_multi_range_cnt_with_name(str, multi_range_cnt);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_multi_range_cnt_with_name(
  spider_string *str,
  uint multi_range_cnt
) {
  int range_cnt_length;
  char range_cnt_str[SPIDER_SQL_INT_LEN];
  DBUG_ENTER("spider_mbase_handler::append_multi_range_cnt_with_name");
  DBUG_PRINT("info",("spider this=%p", this));
  range_cnt_length = my_sprintf(range_cnt_str, (range_cnt_str, "%u",
    multi_range_cnt));
  if (str->reserve(range_cnt_length + SPIDER_SQL_SPACE_LEN +
    SPIDER_SQL_ID_LEN + SPIDER_SQL_COMMA_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(range_cnt_str, range_cnt_length);
  str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
  str->q_append(SPIDER_SQL_ID_STR, SPIDER_SQL_ID_LEN);
  str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_insert_terminator_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_insert_terminator_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_INSERT_SQL:
      str = &insert_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_insert_terminator(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_insert_terminator(
  spider_string *str
) {
  DBUG_ENTER("spider_mbase_handler::append_insert_terminator");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider dup_update_sql.length=%u", dup_update_sql.length()));
  if (
    spider->result_list.insert_dup_update_pushdown &&
    dup_update_sql.length()
  ) {
    DBUG_PRINT("info",("spider add duplicate key update"));
    direct_insert_kind = SPIDER_SQL_DIRECT_INSERT_KIND_DUP_UPDATE;
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
    if (str->reserve(SPIDER_SQL_DUPLICATE_KEY_UPDATE_LEN +
      dup_update_sql.length()))
    {
      str->length(0);
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SQL_DUPLICATE_KEY_UPDATE_STR,
      SPIDER_SQL_DUPLICATE_KEY_UPDATE_LEN);
    if (str->append(dup_update_sql))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  } else {
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_insert_values_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_insert_values_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_INSERT_SQL:
      str = &insert_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_insert_values(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_insert_values(
  spider_string *str
) {
  SPIDER_SHARE *share = spider->share;
  TABLE *table = spider->get_table();
  Field **field;
  bool add_value = FALSE;
  DBUG_ENTER("spider_mbase_handler::append_insert_values");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_OPEN_PAREN_LEN))
  {
    str->length(0);
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  for (field = table->field; *field; field++)
  {
    DBUG_PRINT("info",("spider field_index=%u", (*field)->field_index));
    if (
      bitmap_is_set(table->write_set, (*field)->field_index) ||
      bitmap_is_set(table->read_set, (*field)->field_index)
    ) {
#ifndef DBUG_OFF
      MY_BITMAP *tmp_map =
        dbug_tmp_use_all_columns(table, &table->read_set);
#endif
      add_value = TRUE;
      DBUG_PRINT("info",("spider is_null()=%s",
        (*field)->is_null() ? "TRUE" : "FALSE"));
      DBUG_PRINT("info",("spider table->next_number_field=%p",
        table->next_number_field));
      DBUG_PRINT("info",("spider *field=%p", *field));
      DBUG_PRINT("info",("spider force_auto_increment=%s",
        (table->next_number_field && spider->force_auto_increment) ?
        "TRUE" : "FALSE"));
      if (
        (*field)->is_null() ||
        (
          table->next_number_field == *field &&
          !table->auto_increment_field_not_null &&
          !spider->force_auto_increment
        )
      ) {
        if (str->reserve(SPIDER_SQL_NULL_LEN + SPIDER_SQL_COMMA_LEN))
        {
#ifndef DBUG_OFF
          dbug_tmp_restore_column_map(&table->read_set, tmp_map);
#endif
          str->length(0);
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
        str->q_append(SPIDER_SQL_NULL_STR, SPIDER_SQL_NULL_LEN);
      } else {
        if (spider_db_mbase_utility->append_column_value(
                spider, str, *field, NULL, FALSE, share->access_charset) ||
            str->reserve(SPIDER_SQL_COMMA_LEN))
        {
#ifndef DBUG_OFF
          dbug_tmp_restore_column_map(&table->read_set, tmp_map);
#endif
          str->length(0);
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        }
      }
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
#ifndef DBUG_OFF
      dbug_tmp_restore_column_map(&table->read_set, tmp_map);
#endif
    }
  }
  if (add_value)
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_COMMA_LEN))
  {
    str->length(0);
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_into_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_into_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_INSERT_SQL:
      str = &insert_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_into(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_into(
  spider_string *str
) {
  const TABLE *table = spider->get_table();
  Field **field;
  uint field_name_length = 0;
  DBUG_ENTER("spider_mbase_handler::append_into");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_INTO_LEN + mysql_share->db_nm_max_length +
    SPIDER_SQL_DOT_LEN + mysql_share->table_nm_max_length +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4 + SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_INTO_STR, SPIDER_SQL_INTO_LEN);
  insert_table_name_pos = str->length();
  append_table_name_with_adjusting(str, first_link_idx,
    SPIDER_SQL_TYPE_INSERT_SQL);
  str->q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  for (field = table->field; *field; field++)
  {
    if (
      bitmap_is_set(table->write_set, (*field)->field_index) ||
      bitmap_is_set(table->read_set, (*field)->field_index)
    ) {
      field_name_length =
        mysql_share->column_name_str[(*field)->field_index].length();
      if (str->reserve(field_name_length +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      mysql_share->append_column_name(str, (*field)->field_index);
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
  }
  if (field_name_length)
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  if (str->reserve(SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_VALUES_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  str->q_append(SPIDER_SQL_VALUES_STR, SPIDER_SQL_VALUES_LEN);
  insert_pos = str->length();
  DBUG_RETURN(0);
}

void spider_mbase_handler::set_insert_to_pos(
  ulong sql_type
) {
  DBUG_ENTER("spider_mbase_handler::set_insert_to_pos");
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_INSERT_SQL:
      insert_sql.length(insert_pos);
      break;
    default:
      DBUG_ASSERT(0);
      break;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_handler::append_from_part(
  ulong sql_type,
  int link_idx
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_from_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      str = &update_sql;
      break;
    default:
      str = &sql;
      break;
  }
  error_num = append_from(str, sql_type, link_idx);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_from(
  spider_string *str,
  ulong sql_type,
  int link_idx
) {
  DBUG_ENTER("spider_mbase_handler::append_from");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider link_idx=%d", link_idx));
  int error_num= 0;
  if (str->reserve(SPIDER_SQL_FROM_LEN + mysql_share->db_nm_max_length +
                   SPIDER_SQL_DOT_LEN + mysql_share->table_nm_max_length +
                   /* SPIDER_SQL_NAME_QUOTE_LEN */ 4 +
                   SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_FROM_STR, SPIDER_SQL_FROM_LEN);
  table_name_pos= str->length();
  append_table_name_with_adjusting(str, link_idx, sql_type);
  if (spider_param_index_hint_pushdown(spider->wide_handler->trx->thd))
  {
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_flush_tables_part(int link_idx, bool lock)
{
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_flush_tables_part");
  DBUG_PRINT("info",("spider this=%p", this));

  str= &spider->result_list.sqls[link_idx];
  error_num = append_flush_tables(str, link_idx, lock);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_flush_tables(
  spider_string *str,
  int link_idx,
  bool lock
) {
  DBUG_ENTER("spider_mbase_handler::append_flush_tables");
  DBUG_PRINT("info",("spider this=%p", this));
  if (lock)
  {
    if (str->reserve(SPIDER_SQL_FLUSH_TABLES_LEN +
      SPIDER_SQL_WITH_READ_LOCK_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_FLUSH_TABLES_STR, SPIDER_SQL_FLUSH_TABLES_LEN);
    str->q_append(SPIDER_SQL_WITH_READ_LOCK_STR,
      SPIDER_SQL_WITH_READ_LOCK_LEN);
  } else {
    if (str->reserve(SPIDER_SQL_FLUSH_TABLES_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_FLUSH_TABLES_STR, SPIDER_SQL_FLUSH_TABLES_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_optimize_table_part(int link_idx)
{
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_optimize_table_part");
  DBUG_PRINT("info",("spider this=%p", this));

  str= &spider->result_list.sqls[link_idx];
  error_num = append_optimize_table(str, link_idx);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_optimize_table(
  spider_string *str,
  int link_idx
) {
  SPIDER_SHARE *share = spider->share;
  int conn_link_idx = spider->conn_link_idx[link_idx];
  int local_length = spider_param_internal_optimize_local(
    spider->wide_handler->trx->thd,
    share->internal_optimize_local) * SPIDER_SQL_SQL_LOCAL_LEN;
  DBUG_ENTER("spider_mbase_handler::append_optimize_table");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SQL_OPTIMIZE_LEN + SPIDER_SQL_SQL_TABLE_LEN +
    local_length +
    mysql_share->db_names_str[conn_link_idx].length() +
    SPIDER_SQL_DOT_LEN +
    mysql_share->table_names_str[conn_link_idx].length() +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_SQL_OPTIMIZE_STR, SPIDER_SQL_SQL_OPTIMIZE_LEN);
  if (local_length)
    str->q_append(SPIDER_SQL_SQL_LOCAL_STR, SPIDER_SQL_SQL_LOCAL_LEN);
  str->q_append(SPIDER_SQL_SQL_TABLE_STR, SPIDER_SQL_SQL_TABLE_LEN);
  mysql_share->append_table_name(str, conn_link_idx);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_analyze_table_part(int link_idx)
{
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_analyze_table_part");
  DBUG_PRINT("info",("spider this=%p", this));

  str= &spider->result_list.sqls[link_idx];
  error_num = append_analyze_table(str, link_idx);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_analyze_table(
  spider_string *str,
  int link_idx
) {
  SPIDER_SHARE *share = spider->share;
  int conn_link_idx = spider->conn_link_idx[link_idx];
  int local_length = spider_param_internal_optimize_local(
    spider->wide_handler->trx->thd,
    share->internal_optimize_local) * SPIDER_SQL_SQL_LOCAL_LEN;
  DBUG_ENTER("spider_mbase_handler::append_analyze_table");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SQL_ANALYZE_LEN + SPIDER_SQL_SQL_TABLE_LEN +
    local_length +
    mysql_share->db_names_str[conn_link_idx].length() +
    SPIDER_SQL_DOT_LEN +
    mysql_share->table_names_str[conn_link_idx].length() +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_SQL_ANALYZE_STR, SPIDER_SQL_SQL_ANALYZE_LEN);
  if (local_length)
    str->q_append(SPIDER_SQL_SQL_LOCAL_STR, SPIDER_SQL_SQL_LOCAL_LEN);
  str->q_append(SPIDER_SQL_SQL_TABLE_STR, SPIDER_SQL_SQL_TABLE_LEN);
  mysql_share->append_table_name(str, conn_link_idx);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_repair_table_part(int link_idx,
                                                   HA_CHECK_OPT *check_opt)
{
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_repair_table_part");
  DBUG_PRINT("info",("spider this=%p", this));

  str= &spider->result_list.sqls[link_idx];
  error_num = append_repair_table(str, link_idx, check_opt);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_repair_table(
  spider_string *str,
  int link_idx,
  HA_CHECK_OPT* check_opt
) {
  SPIDER_SHARE *share = spider->share;
  int conn_link_idx = spider->conn_link_idx[link_idx];
  int local_length = spider_param_internal_optimize_local(
    spider->wide_handler->trx->thd,
    share->internal_optimize_local) * SPIDER_SQL_SQL_LOCAL_LEN;
  DBUG_ENTER("spider_mbase_handler::append_repair_table");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SQL_REPAIR_LEN + SPIDER_SQL_SQL_TABLE_LEN +
    local_length +
    mysql_share->db_names_str[conn_link_idx].length() +
    SPIDER_SQL_DOT_LEN +
    mysql_share->table_names_str[conn_link_idx].length() +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_SQL_REPAIR_STR, SPIDER_SQL_SQL_REPAIR_LEN);
  if (local_length)
    str->q_append(SPIDER_SQL_SQL_LOCAL_STR, SPIDER_SQL_SQL_LOCAL_LEN);
  str->q_append(SPIDER_SQL_SQL_TABLE_STR, SPIDER_SQL_SQL_TABLE_LEN);
  mysql_share->append_table_name(str, conn_link_idx);
  if (check_opt->flags & T_QUICK)
  {
    if (str->reserve(SPIDER_SQL_SQL_QUICK_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_QUICK_STR, SPIDER_SQL_SQL_QUICK_LEN);
  }
  if (check_opt->flags & T_EXTEND)
  {
    if (str->reserve(SPIDER_SQL_SQL_EXTENDED_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_EXTENDED_STR, SPIDER_SQL_SQL_EXTENDED_LEN);
  }
  if (check_opt->sql_flags & TT_USEFRM)
  {
    if (str->reserve(SPIDER_SQL_SQL_USE_FRM_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_USE_FRM_STR, SPIDER_SQL_SQL_USE_FRM_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_check_table_part(int link_idx,
                                                  HA_CHECK_OPT *check_opt)
{
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_check_table_part");
  DBUG_PRINT("info",("spider this=%p", this));

  str= &spider->result_list.sqls[link_idx];
  error_num = append_check_table(str, link_idx, check_opt);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_check_table(
  spider_string *str,
  int link_idx,
  HA_CHECK_OPT* check_opt
) {
  int conn_link_idx = spider->conn_link_idx[link_idx];
  DBUG_ENTER("spider_mbase_handler::append_check_table");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SQL_CHECK_TABLE_LEN +
    mysql_share->db_names_str[conn_link_idx].length() +
    SPIDER_SQL_DOT_LEN +
    mysql_share->table_names_str[conn_link_idx].length() +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_SQL_CHECK_TABLE_STR,
    SPIDER_SQL_SQL_CHECK_TABLE_LEN);
  mysql_share->append_table_name(str, conn_link_idx);
  if (check_opt->flags & T_QUICK)
  {
    if (str->reserve(SPIDER_SQL_SQL_QUICK_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_QUICK_STR, SPIDER_SQL_SQL_QUICK_LEN);
  }
  if (check_opt->flags & T_FAST)
  {
    if (str->reserve(SPIDER_SQL_SQL_FAST_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_FAST_STR, SPIDER_SQL_SQL_FAST_LEN);
  }
  if (check_opt->flags & T_MEDIUM)
  {
    if (str->reserve(SPIDER_SQL_SQL_MEDIUM_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_MEDIUM_STR, SPIDER_SQL_SQL_MEDIUM_LEN);
  }
  if (check_opt->flags & T_EXTEND)
  {
    if (str->reserve(SPIDER_SQL_SQL_EXTENDED_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SQL_EXTENDED_STR, SPIDER_SQL_SQL_EXTENDED_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_enable_keys_part(int link_idx)
{
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_enable_keys_part");
  DBUG_PRINT("info",("spider this=%p", this));

  str= &spider->result_list.sqls[link_idx];
  error_num = append_enable_keys(str, link_idx);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_enable_keys(
  spider_string *str,
  int link_idx
) {
  int conn_link_idx = spider->conn_link_idx[link_idx];
  DBUG_ENTER("spider_mbase_handler::append_enable_keys");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SQL_ALTER_TABLE_LEN +
    mysql_share->db_names_str[conn_link_idx].length() +
    SPIDER_SQL_DOT_LEN +
    mysql_share->table_names_str[conn_link_idx].length() +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4 + SPIDER_SQL_SQL_ENABLE_KEYS_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_SQL_ALTER_TABLE_STR,
    SPIDER_SQL_SQL_ALTER_TABLE_LEN);
  mysql_share->append_table_name(str, conn_link_idx);
  str->q_append(SPIDER_SQL_SQL_ENABLE_KEYS_STR,
    SPIDER_SQL_SQL_ENABLE_KEYS_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_disable_keys_part(int link_idx)
{
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_disable_keys_part");
  DBUG_PRINT("info",("spider this=%p", this));

  str= &spider->result_list.sqls[link_idx];
  error_num = append_disable_keys(str, link_idx);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_disable_keys(
  spider_string *str,
  int link_idx
) {
  int conn_link_idx = spider->conn_link_idx[link_idx];
  DBUG_ENTER("spider_mbase_handler::append_disable_keys");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_SQL_ALTER_TABLE_LEN +
    mysql_share->db_names_str[conn_link_idx].length() +
    SPIDER_SQL_DOT_LEN +
    mysql_share->table_names_str[conn_link_idx].length() +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4 + SPIDER_SQL_SQL_DISABLE_KEYS_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_SQL_ALTER_TABLE_STR,
    SPIDER_SQL_SQL_ALTER_TABLE_LEN);
  mysql_share->append_table_name(str, conn_link_idx);
  str->q_append(SPIDER_SQL_SQL_DISABLE_KEYS_STR,
    SPIDER_SQL_SQL_DISABLE_KEYS_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_delete_all_rows_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_delete_all_rows_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_DELETE_SQL:
      str = &update_sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_delete_all_rows(str, sql_type);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_delete_all_rows(
  spider_string *str,
  ulong sql_type
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_delete_all_rows");
  DBUG_PRINT("info",("spider this=%p", this));
  if (spider->wide_handler->sql_command == SQLCOM_TRUNCATE)
  {
    if ((error_num = append_truncate(str, sql_type, first_link_idx)))
      DBUG_RETURN(error_num);
  } else {
    if (
      (error_num = append_delete(str)) ||
      (error_num = append_from(str, sql_type, first_link_idx))
    )
      DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_truncate(
  spider_string *str,
  ulong sql_type,
  int link_idx
) {
  DBUG_ENTER("spider_mbase_handler::append_truncate");
  if (str->reserve(SPIDER_SQL_TRUNCATE_TABLE_LEN +
    mysql_share->db_nm_max_length +
    SPIDER_SQL_DOT_LEN + mysql_share->table_nm_max_length +
    /* SPIDER_SQL_NAME_QUOTE_LEN */ 4 + SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  str->q_append(SPIDER_SQL_TRUNCATE_TABLE_STR, SPIDER_SQL_TRUNCATE_TABLE_LEN);
  table_name_pos = str->length();
  append_table_name_with_adjusting(str, link_idx, sql_type);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_explain_select_part(
  const key_range *start_key,
  const key_range *end_key,
  ulong sql_type,
  int link_idx
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_explain_select_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_OTHER_SQL:
      str = &spider->result_list.sqls[link_idx];
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num =
    append_explain_select(str, start_key, end_key, sql_type, link_idx);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_explain_select(
  spider_string *str,
  const key_range *start_key,
  const key_range *end_key,
  ulong sql_type,
  int link_idx
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_explain_select");
  DBUG_PRINT("info",("spider this=%p", this));
  if (str->reserve(SPIDER_SQL_EXPLAIN_SELECT_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  str->q_append(SPIDER_SQL_EXPLAIN_SELECT_STR, SPIDER_SQL_EXPLAIN_SELECT_LEN);
  if (
    (error_num = append_from(str, sql_type, link_idx)) ||
    (error_num = append_key_where(str, NULL, NULL, start_key, end_key,
      sql_type, FALSE))
  ) {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  DBUG_RETURN(0);
}

/********************************************************************
 * Determine whether the current query's projection list
 * consists solely of the specified column.
 *
 * Params   IN      - field_index:
 *                    Field index of the column of interest within
 *                    its table.
 *
 * Returns  TRUE    - if the query's projection list consists
 *                    solely of the specified column.
 *          FALSE   - otherwise.
 ********************************************************************/
bool spider_mbase_handler::is_sole_projection_field(
  uint16 field_index
) {
  // Determine whether the projection list consists solely of the field of interest
  bool            is_field_in_projection_list = FALSE;
  TABLE*          table                       = spider->get_table();
  uint16          projection_field_count      = 0;
  uint16          projection_field_index;
  Field**         field;
  DBUG_ENTER( "spider_mbase_handler::is_sole_projection_field" );

  for ( field = table->field; *field ; field++ )
  {
    projection_field_index = ( *field )->field_index;

    if ( !( minimum_select_bit_is_set( projection_field_index ) ) )
    {
      // Current field is not in the projection list
      continue;
    }

    projection_field_count++;

    if ( !is_field_in_projection_list )
    {
      if ( field_index == projection_field_index )
      {
        // Field of interest is in the projection list
        is_field_in_projection_list = TRUE;
      }
    }

    if ( is_field_in_projection_list && ( projection_field_count != 1 ) )
    {
      // Field of interest is not the sole column in the projection list
      DBUG_RETURN( FALSE );
    }
  }

  if ( is_field_in_projection_list && ( projection_field_count == 1 ) )
  {
    // Field of interest is the only column in the projection list
    DBUG_RETURN( TRUE );
  }

  DBUG_RETURN( FALSE );
}

bool spider_mbase_handler::is_bulk_insert_exec_period(
  bool bulk_end
) {
  DBUG_ENTER("spider_mbase_handler::is_bulk_insert_exec_period");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider insert_sql.length=%u", insert_sql.length()));
  DBUG_PRINT("info",("spider insert_pos=%d", insert_pos));
  DBUG_PRINT("info",("spider insert_sql=%s", insert_sql.c_ptr_safe()));
  if (
    (bulk_end || (int) insert_sql.length() >= spider->bulk_size) &&
    (int) insert_sql.length() > insert_pos
  ) {
    DBUG_RETURN(TRUE);
  }
  DBUG_RETURN(FALSE);
}

bool spider_mbase_handler::sql_is_filled_up(
  ulong sql_type
) {
  DBUG_ENTER("spider_mbase_handler::sql_is_filled_up");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(filled_up);
}

bool spider_mbase_handler::sql_is_empty(
  ulong sql_type
) {
  bool is_empty;
  DBUG_ENTER("spider_mbase_handler::sql_is_empty");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      is_empty = (sql.length() == 0);
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
      is_empty = (insert_sql.length() == 0);
      break;
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      is_empty = (update_sql.length() == 0);
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      is_empty = (tmp_sql.length() == 0);
      break;
    default:
      is_empty = TRUE;
      break;
  }
  DBUG_RETURN(is_empty);
}

bool spider_mbase_handler::support_multi_split_read()
{
  DBUG_ENTER("spider_mbase_handler::support_multi_split_read");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

bool spider_mbase_handler::support_bulk_update()
{
  DBUG_ENTER("spider_mbase_handler::support_bulk_update");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(TRUE);
}

int spider_mbase_handler::bulk_tmp_table_insert()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::bulk_tmp_table_insert");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = store_sql_to_bulk_tmp_table(&update_sql, upd_tmp_tbl);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::bulk_tmp_table_insert(
  int link_idx
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::bulk_tmp_table_insert");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = store_sql_to_bulk_tmp_table(
    &spider->result_list.update_sqls[link_idx],
    spider->result_list.upd_tmp_tbls[link_idx]);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::bulk_tmp_table_end_bulk_insert()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::bulk_tmp_table_end_bulk_insert");
  DBUG_PRINT("info",("spider this=%p", this));
  if ((error_num = upd_tmp_tbl->file->ha_end_bulk_insert()))
  {
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::bulk_tmp_table_rnd_init()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::bulk_tmp_table_rnd_init");
  DBUG_PRINT("info",("spider this=%p", this));
  upd_tmp_tbl->file->extra(HA_EXTRA_CACHE);
  if ((error_num = upd_tmp_tbl->file->ha_rnd_init(TRUE)))
  {
    DBUG_RETURN(error_num);
  }
  reading_from_bulk_tmp_table = TRUE;
  DBUG_RETURN(0);
}

int spider_mbase_handler::bulk_tmp_table_rnd_next()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::bulk_tmp_table_rnd_next");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = upd_tmp_tbl->file->ha_rnd_next(upd_tmp_tbl->record[0]);
  if (!error_num)
  {
    error_num = restore_sql_from_bulk_tmp_table(&insert_sql, upd_tmp_tbl);
  }
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::bulk_tmp_table_rnd_end()
{
  int error_num;
  DBUG_ENTER("spider_mbase_handler::bulk_tmp_table_rnd_end");
  DBUG_PRINT("info",("spider this=%p", this));
  reading_from_bulk_tmp_table = FALSE;
  if ((error_num = upd_tmp_tbl->file->ha_rnd_end()))
  {
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

bool spider_mbase_handler::need_copy_for_update(
  int link_idx
) {
  int all_link_idx = spider->conn_link_idx[link_idx];
  DBUG_ENTER("spider_mbase_handler::need_copy_for_update");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(!mysql_share->same_db_table_name ||
    spider->share->link_statuses[all_link_idx] == SPIDER_LINK_STATUS_RECOVERY);
}

bool spider_mbase_handler::bulk_tmp_table_created()
{
  DBUG_ENTER("spider_mbase_handler::bulk_tmp_table_created");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(upd_tmp_tbl);
}

int spider_mbase_handler::mk_bulk_tmp_table_and_bulk_start()
{
  THD *thd = spider->wide_handler->trx->thd;
  TABLE *table = spider->get_table();
  DBUG_ENTER("spider_mbase_handler::mk_bulk_tmp_table_and_bulk_start");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!upd_tmp_tbl)
  {
    LEX_CSTRING field_name = {STRING_WITH_LEN("a")};
    if (!(upd_tmp_tbl = spider_mk_sys_tmp_table(
      thd, table, &upd_tmp_tbl_prm, &field_name, update_sql.charset())))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    upd_tmp_tbl->file->extra(HA_EXTRA_WRITE_CACHE);
    upd_tmp_tbl->file->ha_start_bulk_insert((ha_rows) 0);
  }
  DBUG_RETURN(0);
}

void spider_mbase_handler::rm_bulk_tmp_table()
{
  DBUG_ENTER("spider_mbase_handler::rm_bulk_tmp_table");
  DBUG_PRINT("info",("spider this=%p", this));
  if (upd_tmp_tbl)
  {
    spider_rm_sys_tmp_table(spider->wide_handler->trx->thd, upd_tmp_tbl,
      &upd_tmp_tbl_prm);
    upd_tmp_tbl = NULL;
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_handler::store_sql_to_bulk_tmp_table(
  spider_string *str,
  TABLE *tmp_table
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::store_sql_to_bulk_tmp_table");
  DBUG_PRINT("info",("spider this=%p", this));
  tmp_table->field[0]->set_notnull();
  tmp_table->field[0]->store(str->ptr(), str->length(), str->charset());
  if ((error_num = tmp_table->file->ha_write_row(tmp_table->record[0])))
    DBUG_RETURN(error_num);
  DBUG_RETURN(0);
}

int spider_mbase_handler::restore_sql_from_bulk_tmp_table(
  spider_string *str,
  TABLE *tmp_table
) {
  DBUG_ENTER("spider_mbase_handler::restore_sql_from_bulk_tmp_table");
  DBUG_PRINT("info",("spider this=%p", this));
  tmp_table->field[0]->val_str(str->get_str());
  str->mem_calc();
  DBUG_RETURN(0);
}

int spider_mbase_handler::insert_lock_tables_list(
  SPIDER_CONN *conn,
  int link_idx
) {
  spider_db_mbase *db_conn = (spider_db_mbase *) conn->db_conn;
  SPIDER_LINK_FOR_HASH *tmp_link_for_hash2 = &link_for_hash[link_idx];
  DBUG_ENTER("spider_mbase_handler::insert_lock_tables_list");
  DBUG_PRINT("info",("spider this=%p", this));
  uint old_elements =
    db_conn->lock_table_hash.array.max_element;
  if (my_hash_insert(&db_conn->lock_table_hash,
    (uchar*) tmp_link_for_hash2))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  if (db_conn->lock_table_hash.array.max_element > old_elements)
  {
    spider_alloc_calc_mem(spider_current_trx,
      db_conn->lock_table_hash,
      (db_conn->lock_table_hash.array.max_element - old_elements) *
      db_conn->lock_table_hash.array.size_of_element);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_lock_tables_list(
  SPIDER_CONN *conn,
  int link_idx,
  int *appended
) {
  int error_num;
  SPIDER_LINK_FOR_HASH *tmp_link_for_hash, *tmp_link_for_hash2;
  int conn_link_idx = spider->conn_link_idx[link_idx];
  spider_db_mbase *db_conn = (spider_db_mbase *) conn->db_conn;
  DBUG_ENTER("spider_mbase_handler::append_lock_tables_list");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider db_conn=%p", db_conn));
  tmp_link_for_hash2 = &link_for_hash[link_idx];
  tmp_link_for_hash2->db_table_str =
    &mysql_share->db_table_str[conn_link_idx];
  DBUG_PRINT("info",("spider db_table_str=%s",
    tmp_link_for_hash2->db_table_str->c_ptr_safe()));
  tmp_link_for_hash2->db_table_str_hash_value =
    mysql_share->db_table_str_hash_value[conn_link_idx];
  if (!(tmp_link_for_hash = (SPIDER_LINK_FOR_HASH *)
    my_hash_search_using_hash_value(
      &db_conn->lock_table_hash,
      tmp_link_for_hash2->db_table_str_hash_value,
      (uchar*) tmp_link_for_hash2->db_table_str->ptr(),
      tmp_link_for_hash2->db_table_str->length())))
  {
    if ((error_num = insert_lock_tables_list(conn, link_idx)))
      DBUG_RETURN(error_num);
    *appended = 1;
  } else {
    if (tmp_link_for_hash->spider->wide_handler->lock_type <
      spider->wide_handler->lock_type)
    {
      my_hash_delete(&db_conn->lock_table_hash,
        (uchar*) tmp_link_for_hash);
      uint old_elements =
        db_conn->lock_table_hash.array.max_element;
      if (my_hash_insert(&db_conn->lock_table_hash,
        (uchar*) tmp_link_for_hash2))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      if (db_conn->lock_table_hash.array.max_element > old_elements)
      {
        spider_alloc_calc_mem(spider_current_trx,
          db_conn->lock_table_hash,
          (db_conn->lock_table_hash.array.max_element - old_elements) *
          db_conn->lock_table_hash.array.size_of_element);
      }
    }
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::realloc_sql(
  ulong *realloced
) {
  THD *thd = spider->wide_handler->trx->thd;
  st_spider_share *share = spider->share;
  int init_sql_alloc_size =
    spider_param_init_sql_alloc_size(thd, share->init_sql_alloc_size);
  DBUG_ENTER("spider_mbase_handler::realloc_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  if ((int) sql.alloced_length() > init_sql_alloc_size * 2)
  {
    sql.free();
    if (sql.real_alloc(init_sql_alloc_size))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    *realloced |= SPIDER_SQL_TYPE_SELECT_SQL;
  }
  if ((int) ha_sql.alloced_length() > init_sql_alloc_size * 2)
  {
    ha_sql.free();
    if (ha_sql.real_alloc(init_sql_alloc_size))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    *realloced |= SPIDER_SQL_TYPE_SELECT_SQL;
  }
  if ((int) dup_update_sql.alloced_length() > init_sql_alloc_size * 2)
  {
    dup_update_sql.free();
    if (dup_update_sql.real_alloc(init_sql_alloc_size))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  if ((int) insert_sql.alloced_length() > init_sql_alloc_size * 2)
  {
    insert_sql.free();
    if (insert_sql.real_alloc(init_sql_alloc_size))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    *realloced |= SPIDER_SQL_TYPE_INSERT_SQL;
  }
  if ((int) update_sql.alloced_length() > init_sql_alloc_size * 2)
  {
    update_sql.free();
    if (update_sql.real_alloc(init_sql_alloc_size))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    *realloced |= (SPIDER_SQL_TYPE_UPDATE_SQL | SPIDER_SQL_TYPE_DELETE_SQL);
  }
  update_sql.length(0);
  if ((int) tmp_sql.alloced_length() > init_sql_alloc_size * 2)
  {
    tmp_sql.free();
    if (tmp_sql.real_alloc(init_sql_alloc_size))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    *realloced |= SPIDER_SQL_TYPE_TMP_SQL;
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::reset_sql(
  ulong sql_type
) {
  DBUG_ENTER("spider_mbase_handler::reset_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql_type & SPIDER_SQL_TYPE_SELECT_SQL)
  {
    sql.length(0);
  }
  if (sql_type & SPIDER_SQL_TYPE_INSERT_SQL)
  {
    insert_sql.length(0);
  }
  if (sql_type & (SPIDER_SQL_TYPE_UPDATE_SQL | SPIDER_SQL_TYPE_DELETE_SQL |
    SPIDER_SQL_TYPE_BULK_UPDATE_SQL))
  {
    update_sql.length(0);
  }
  if (sql_type & SPIDER_SQL_TYPE_TMP_SQL)
  {
    tmp_sql.length(0);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::set_sql_for_exec(
  ulong sql_type,
  int link_idx,
  SPIDER_LINK_IDX_CHAIN *link_idx_chain
) {
  DBUG_ENTER("spider_mbase_handler::set_sql_for_exec");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql_type & SPIDER_SQL_TYPE_SELECT_SQL)
  {
    exec_sql = &sql;
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::set_sql_for_exec(
  ulong sql_type,
  int link_idx
) {
  int error_num;
  uint tmp_pos;
  SPIDER_SHARE *share = spider->share;
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  int all_link_idx = spider->conn_link_idx[link_idx];
  DBUG_ENTER("spider_mbase_handler::set_sql_for_exec");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql_type & (SPIDER_SQL_TYPE_SELECT_SQL | SPIDER_SQL_TYPE_TMP_SQL))
  {
    if (mysql_share->same_db_table_name || link_idx == first_link_idx)
    {
      if (sql_type & SPIDER_SQL_TYPE_SELECT_SQL)
        exec_sql = &sql;
      if (sql_type & SPIDER_SQL_TYPE_TMP_SQL)
        exec_tmp_sql = &tmp_sql;
    } else {
      char tmp_table_name[MAX_FIELD_WIDTH * 2],
        tgt_table_name[MAX_FIELD_WIDTH * 2];
      int tmp_table_name_length;
      spider_string tgt_table_name_str(tgt_table_name,
        MAX_FIELD_WIDTH * 2,
        mysql_share->db_names_str[link_idx].charset());
      const char *table_names[2], *table_aliases[2];
      uint table_name_lengths[2], table_alias_lengths[2];
      tgt_table_name_str.init_calc_mem(SPD_MID_MBASE_HANDLER_SET_SQL_FOR_EXEC_1);
      tgt_table_name_str.length(0);
      if (result_list->tmp_table_join && spider->bka_mode != 2)
      {
        create_tmp_bka_table_name(tmp_table_name, &tmp_table_name_length,
          link_idx);
        append_table_name_with_adjusting(&tgt_table_name_str, link_idx,
          SPIDER_SQL_TYPE_TMP_SQL);
        table_names[0] = tmp_table_name;
        table_names[1] = tgt_table_name_str.ptr();
        table_name_lengths[0] = tmp_table_name_length;
        table_name_lengths[1] = tgt_table_name_str.length();
        table_aliases[0] = SPIDER_SQL_A_STR;
        table_aliases[1] = SPIDER_SQL_B_STR;
        table_alias_lengths[0] = SPIDER_SQL_A_LEN;
        table_alias_lengths[1] = SPIDER_SQL_B_LEN;
      }
      if (sql_type & SPIDER_SQL_TYPE_SELECT_SQL)
      {
        exec_sql = &result_list->sqls[link_idx];
        if (exec_sql->copy(sql))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        else if (result_list->use_union)
        {
          if ((error_num = reset_union_table_name(exec_sql, link_idx,
            SPIDER_SQL_TYPE_SELECT_SQL)))
            DBUG_RETURN(error_num);
        } else {
          tmp_pos = exec_sql->length();
          exec_sql->length(table_name_pos);
          if (result_list->tmp_table_join && spider->bka_mode != 2)
          {
            if ((error_num = spider_db_mbase_utility->append_from_with_alias(
              exec_sql, table_names, table_name_lengths,
              table_aliases, table_alias_lengths, 2,
              &table_name_pos, TRUE))
            )
              DBUG_RETURN(error_num);
            exec_sql->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
          } else {
            append_table_name_with_adjusting(exec_sql, link_idx,
              SPIDER_SQL_TYPE_SELECT_SQL);
          }
          exec_sql->length(tmp_pos);
        }
      }
      if (sql_type & SPIDER_SQL_TYPE_TMP_SQL)
      {
        exec_tmp_sql = &result_list->tmp_sqls[link_idx];
        if (result_list->tmp_table_join && spider->bka_mode != 2)
        {
          if (exec_tmp_sql->copy(tmp_sql))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          else {
            tmp_pos = exec_tmp_sql->length();
            exec_tmp_sql->length(tmp_sql_pos1);
            exec_tmp_sql->q_append(tmp_table_name, tmp_table_name_length);
            exec_tmp_sql->length(tmp_sql_pos2);
            exec_tmp_sql->q_append(tmp_table_name, tmp_table_name_length);
            exec_tmp_sql->length(tmp_sql_pos3);
            exec_tmp_sql->q_append(tmp_table_name, tmp_table_name_length);
            exec_tmp_sql->length(tmp_pos);
          }
        }
      }
    }
  }
  if (sql_type & SPIDER_SQL_TYPE_INSERT_SQL)
  {
    if (mysql_share->same_db_table_name || link_idx == first_link_idx)
      exec_insert_sql = &insert_sql;
    else {
      exec_insert_sql = &result_list->insert_sqls[link_idx];
      if (exec_insert_sql->copy(insert_sql))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      DBUG_PRINT("info",("spider exec_insert_sql=%s",
        exec_insert_sql->c_ptr_safe()));
      tmp_pos = exec_insert_sql->length();
      exec_insert_sql->length(insert_table_name_pos);
      append_table_name_with_adjusting(exec_insert_sql, link_idx,
        sql_type);
      exec_insert_sql->length(tmp_pos);
      DBUG_PRINT("info",("spider exec_insert_sql->length=%u",
        exec_insert_sql->length()));
      DBUG_PRINT("info",("spider exec_insert_sql=%s",
        exec_insert_sql->c_ptr_safe()));
    }
  }
  if (sql_type & SPIDER_SQL_TYPE_BULK_UPDATE_SQL)
  {
    if (reading_from_bulk_tmp_table)
    {
      if (
        mysql_share->same_db_table_name &&
        share->link_statuses[all_link_idx] != SPIDER_LINK_STATUS_RECOVERY
      ) {
        exec_update_sql = &insert_sql;
      } else if (!spider->result_list.upd_tmp_tbls[link_idx])
      {
        DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM);
      } else {
        exec_update_sql = &spider->result_list.insert_sqls[link_idx];
        if ((error_num = restore_sql_from_bulk_tmp_table(exec_update_sql,
          spider->result_list.upd_tmp_tbls[link_idx])))
        {
          DBUG_RETURN(error_num);
        }
      }
    } else {
      if (
        mysql_share->same_db_table_name &&
        share->link_statuses[all_link_idx] != SPIDER_LINK_STATUS_RECOVERY
      ) {
        exec_update_sql = &update_sql;
      } else {
        exec_update_sql = &spider->result_list.update_sqls[link_idx];
      }
    }
  } else if (sql_type &
    (SPIDER_SQL_TYPE_UPDATE_SQL | SPIDER_SQL_TYPE_DELETE_SQL))
  {
    if (mysql_share->same_db_table_name || link_idx == first_link_idx)
      exec_update_sql = &update_sql;
    else {
      exec_update_sql = &spider->result_list.update_sqls[link_idx];
      if (exec_update_sql->copy(update_sql))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      tmp_pos = exec_update_sql->length();
      exec_update_sql->length(table_name_pos);
      append_table_name_with_adjusting(exec_update_sql, link_idx,
        sql_type);
      exec_update_sql->length(tmp_pos);
    }
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::set_sql_for_exec(
  spider_db_copy_table *tgt_ct,
  ulong sql_type
) {
  spider_mbase_copy_table *mysql_ct = (spider_mbase_copy_table *) tgt_ct;
  DBUG_ENTER("spider_mbase_handler::set_sql_for_exec");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_INSERT_SQL:
      exec_insert_sql = &mysql_ct->sql;
      break;
    default:
      DBUG_ASSERT(0);
      break;
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::execute_sql(
  ulong sql_type,
  SPIDER_CONN *conn,
  int quick_mode,
  int *need_mon
) {
  spider_string *tgt_sql;
  uint tgt_length;
  DBUG_ENTER("spider_mbase_handler::execute_sql");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      DBUG_PRINT("info",("spider SPIDER_SQL_TYPE_SELECT_SQL"));
      tgt_sql = exec_sql;
      tgt_length = tgt_sql->length();
      break;
    case SPIDER_SQL_TYPE_INSERT_SQL:
      DBUG_PRINT("info",("spider SPIDER_SQL_TYPE_SELECT_SQL"));
      tgt_sql = exec_insert_sql;
      tgt_length = tgt_sql->length();
      break;
    case SPIDER_SQL_TYPE_UPDATE_SQL:
    case SPIDER_SQL_TYPE_DELETE_SQL:
    case SPIDER_SQL_TYPE_BULK_UPDATE_SQL:
      DBUG_PRINT("info",("spider %s",
        sql_type == SPIDER_SQL_TYPE_UPDATE_SQL ? "SPIDER_SQL_TYPE_UPDATE_SQL" :
        sql_type == SPIDER_SQL_TYPE_DELETE_SQL ? "SPIDER_SQL_TYPE_DELETE_SQL" :
        "SPIDER_SQL_TYPE_BULK_UPDATE_SQL"
      ));
      tgt_sql = exec_update_sql;
      tgt_length = tgt_sql->length();
      break;
    case SPIDER_SQL_TYPE_TMP_SQL:
      DBUG_PRINT("info",("spider SPIDER_SQL_TYPE_TMP_SQL"));
      tgt_sql = exec_tmp_sql;
      tgt_length = tgt_sql->length();
      break;
    case SPIDER_SQL_TYPE_DROP_TMP_TABLE_SQL:
      DBUG_PRINT("info",("spider SPIDER_SQL_TYPE_DROP_TMP_TABLE_SQL"));
      tgt_sql = exec_tmp_sql;
      tgt_length = tmp_sql_pos5;
      break;
    default:
      /* nothing to do */
      DBUG_PRINT("info",("spider default"));
      DBUG_RETURN(0);
  }
  DBUG_RETURN(spider_db_query(
    conn,
    tgt_sql->ptr(),
    tgt_length,
    quick_mode,
    need_mon
  ));
}

int spider_mbase_handler::reset()
{
  DBUG_ENTER("spider_mbase_handler::reset");
  DBUG_PRINT("info",("spider this=%p", this));
  update_sql.length(0);
  DBUG_RETURN(0);
}

int spider_mbase_handler::sts_mode_exchange(
  int sts_mode
) {
  DBUG_ENTER("spider_mbase_handler::sts_mode_exchange");
  DBUG_PRINT("info",("spider sts_mode=%d", sts_mode));
  DBUG_RETURN(sts_mode);
}

/** Set the session lock wait time out */
static int spider_set_lock_wait_timeout(uint seconds, SPIDER_CONN *conn,
                                        int *need_mon)
{
  char query[512];
  int error_num;
  DBUG_ENTER("spider_db_set_lock_wait_timeout");
  size_t query_len =
    my_snprintf(query, sizeof(query),
              "set @old_lock_wait_timeout=@@session.lock_wait_timeout;"
              "set session lock_wait_timeout=%d;",
              seconds);
  DEBUG_SYNC(conn->thd, "spider_set_lock_wait_timeout_before_query");
  if (spider_db_query(conn, query, query_len, -1, need_mon))
    DBUG_RETURN(spider_db_errorno(conn));
  spider_db_result *result;
  do {
    st_spider_db_request_key request_key= {1, 1, NULL, 1, NULL};
    if ((result = conn->db_conn->store_result(NULL, &request_key,
                                              &error_num)))
    {
      result->free_result();
      delete result;
    } else if ((error_num = conn->db_conn->get_errno()))
      break;
  } while (!(error_num = conn->db_conn->next_result()));
  DBUG_RETURN(0);
}

/** Reset the session lock wait time out */
int spider_db_mbase::reset_lock_wait_timeout()
{
  const LEX_CSTRING query = {STRING_WITH_LEN(
      "set session lock_wait_timeout=@old_lock_wait_timeout;")};
  int error_num;
  DBUG_ENTER("spider_db_set_lock_wait_timeout");
  if ((error_num = exec_query(query.str, query.length, -1)))
    DBUG_RETURN(error_num);
  spider_db_result *result;
  do {
    st_spider_db_request_key request_key= {1, 1, NULL, 1, NULL};
    if ((result = conn->db_conn->store_result(NULL, &request_key,
                                              &error_num)))
    {
      result->free_result();
      delete result;
    } else if ((error_num = conn->db_conn->get_errno()))
      break;
  } while (!(error_num= conn->db_conn->next_result()));
  DBUG_RETURN(0);
}

/**
  Executes show table status query and stores results in share->stat
*/
int spider_mbase_handler::show_table_status(
  int link_idx,
  int sts_mode,
  uint flag
) {
  int error_num;
  SPIDER_CONN *conn = spider->conns[link_idx];
  SPIDER_DB_RESULT *res;
  SPIDER_SHARE *share = spider->share;
  const uint pos = 2 * spider->conn_link_idx[link_idx] +
    (sts_mode == 1 ? 0 : 1);
  ulonglong auto_increment_value = 0;
  DBUG_ENTER("spider_mbase_handler::show_table_status");
  DBUG_PRINT("info",("spider sts_mode=%d", sts_mode));

  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  conn->disable_connect_retry = TRUE;
  spider_conn_set_timeout_from_share(
    conn, link_idx, spider->wide_handler->trx->thd, share);

  if ((error_num = spider_db_set_names(spider, conn, link_idx)) ||
      (error_num = spider_set_lock_wait_timeout(
        1, conn, &spider->need_mons[link_idx])) ||
      /* Executes the `show table status` query */
      (spider_db_query(
        conn,
        mysql_share->show_table_status[pos].ptr(),
        mysql_share->show_table_status[pos].length(),
        -1,
        &spider->need_mons[link_idx]) &&
       (error_num = spider_db_errorno(conn))))
  {
    if (error_num == ER_SPIDER_REMOTE_SERVER_GONE_AWAY_NUM &&
        !conn->disable_reconnect)
    {
      /* retry */
      if ((error_num = spider_db_ping(spider, conn, link_idx)))
        goto unlock;
      if ((error_num = spider_db_set_names(spider, conn, link_idx)))
        goto unlock;
      spider_conn_set_timeout_from_share(conn, link_idx,
                                         spider->wide_handler->trx->thd,
                                         share);
      if ((error_num =
           spider_set_lock_wait_timeout(1, conn, &spider->need_mons[link_idx])))
        goto unlock;
      if (spider_db_query(
            conn,
            mysql_share->show_table_status[pos].ptr(),
            mysql_share->show_table_status[pos].length(),
            -1,
            &spider->need_mons[link_idx])
      ) {
        goto unlock;
      }
    } else
      goto unlock;
  }
  error_num= 0;
  st_spider_db_request_key request_key;
  request_key.spider_thread_id = spider->wide_handler->trx->spider_thread_id;
  request_key.query_id = spider->wide_handler->trx->thd->query_id;
  request_key.handler = spider;
  request_key.request_id = 1;
  request_key.next = NULL;
  if (spider_param_dry_access())
    goto unlock;
  if (!(res = conn->db_conn->store_result(NULL, &request_key, &error_num)))
  {
    if (error_num || (error_num = spider_db_errorno(conn)))
      goto unlock;
    else if (sts_mode == 1)
    {
      my_printf_error(
        ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM,
        ER_SPIDER_REMOTE_TABLE_NOT_FOUND_STR, MYF(0),
        mysql_share->db_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe(),
        mysql_share->table_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe());
      error_num= ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM;
      goto unlock;
    } else                      /* get from information schema */
    {
      error_num= ER_QUERY_ON_FOREIGN_DATA_SOURCE;
      goto unlock;
    }
  }
  /* Fetches query results into share->stat. */
  error_num = res->fetch_table_status(sts_mode, share->stat);
  auto_increment_value = share->stat.auto_increment_value;
  res->free_result();
  delete res;
  if (error_num)
  {
    switch (error_num)
    {
    case ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM:
      my_printf_error(
        ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM,
        ER_SPIDER_REMOTE_TABLE_NOT_FOUND_STR, MYF(0),
        mysql_share->db_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe(),
        mysql_share->table_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe());
      break;
    case ER_SPIDER_INVALID_REMOTE_TABLE_INFO_NUM:
      my_printf_error(
        ER_SPIDER_INVALID_REMOTE_TABLE_INFO_NUM,
        ER_SPIDER_INVALID_REMOTE_TABLE_INFO_STR, MYF(0),
        mysql_share->db_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe(),
        mysql_share->table_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe());
      break;
    default:
      break;
    }
    goto unlock;
  }
  if ((error_num = ((spider_db_mbase *) conn->db_conn)->fetch_and_print_warnings(NULL)))
  {
    ((spider_db_mbase *) conn->db_conn)->reset_lock_wait_timeout();
    if (error_num == ER_LOCK_WAIT_TIMEOUT)
    {
      error_num = ER_SPIDER_TABLE_OPEN_LOCK_WAIT_TIMEOUT_NUM;
      my_printf_error(
        ER_SPIDER_TABLE_OPEN_LOCK_WAIT_TIMEOUT_NUM,
        ER_SPIDER_TABLE_OPEN_LOCK_WAIT_TIMEOUT_STR, MYF(0),
        mysql_share->db_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe(),
        mysql_share->table_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe());
    }
    goto unlock;
  }
  if ((error_num =
       ((spider_db_mbase *) conn->db_conn)->reset_lock_wait_timeout()))
    goto unlock;
  if (share->static_records_for_status != -1)
    share->stat.records = (ha_rows) share->static_records_for_status;
  if (share->static_mean_rec_length != -1)
    share->stat.mean_rec_length = (ulong) share->static_mean_rec_length;
  if (auto_increment_value > share->lgtm_tblhnd_share->auto_increment_value)
  {
    share->lgtm_tblhnd_share->auto_increment_value = auto_increment_value;
    DBUG_PRINT("info",("spider auto_increment_value=%llu",
                       share->lgtm_tblhnd_share->auto_increment_value));
  }
unlock:
  conn->disable_connect_retry = FALSE;
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::crd_mode_exchange(
  int crd_mode
) {
  DBUG_ENTER("spider_mbase_handler::crd_mode_exchange");
  DBUG_PRINT("info",("spider crd_mode=%d", crd_mode));
  DBUG_RETURN(crd_mode);
}

int spider_mbase_handler::show_index(
  int link_idx,
  int crd_mode
) {
  int error_num;
  SPIDER_CONN *conn = spider->conns[link_idx];
  SPIDER_SHARE *share = spider->share;
  TABLE *table = spider->get_table();
  SPIDER_DB_RESULT *res;
  int field;
  longlong *tmp_crd;
  const uint pos = 2 * spider->conn_link_idx[link_idx] +
    (crd_mode == 1 ? 0 : 1);
  DBUG_ENTER("spider_mbase_handler::show_index");
  DBUG_PRINT("info",("spider crd_mode=%d", crd_mode));
  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  spider_conn_set_timeout_from_share(conn, link_idx,
                                     spider->wide_handler->trx->thd, share);
  if ((error_num = spider_db_set_names(spider, conn, link_idx)) ||
      (error_num =
       spider_set_lock_wait_timeout(1, conn, &spider->need_mons[link_idx])) ||
      (spider_db_query(
        conn,
        mysql_share->show_index[pos].ptr(),
        mysql_share->show_index[pos].length(),
        -1,
        &spider->need_mons[link_idx]) &&
       (error_num = spider_db_errorno(conn))))
  {
    if (error_num == ER_SPIDER_REMOTE_SERVER_GONE_AWAY_NUM &&
        !conn->disable_reconnect)
    {
      /* retry */
      if ((error_num = spider_db_ping(spider, conn, link_idx)))
        goto unlock;
      if ((error_num = spider_db_set_names(spider, conn, link_idx)))
        goto unlock;
      spider_conn_set_timeout_from_share(conn, link_idx,
                                         spider->wide_handler->trx->thd,
                                         share);
      if ((error_num =
           spider_set_lock_wait_timeout(1, conn, &spider->need_mons[link_idx])))
        goto unlock;
      if (spider_db_query(
            conn,
            mysql_share->show_index[pos].ptr(),
            mysql_share->show_index[pos].length(),
            -1,
            &spider->need_mons[link_idx]))
      {
        error_num= spider_db_errorno(conn);
        goto unlock;
      }
    } else
      goto unlock;
  }
  error_num= 0;
  st_spider_db_request_key request_key;
  request_key.spider_thread_id = spider->wide_handler->trx->spider_thread_id;
  request_key.query_id = spider->wide_handler->trx->thd->query_id;
  request_key.handler = spider;
  request_key.request_id = 1;
  request_key.next = NULL;
  if (!(res = conn->db_conn->store_result(NULL, &request_key, &error_num)))
  {
    if (error_num || (error_num = spider_db_errorno(conn)))
      goto unlock;
    /* no record is ok */
  }
  if (res)
    error_num = res->fetch_table_cardinality(
      crd_mode, table, share->cardinality, share->cardinality_upd,
      share->bitmap_size);
  for (field = 0, tmp_crd = share->cardinality;
       field < (int) table->s->fields;
       field++, tmp_crd++)
  {
    if (!spider_bit_is_set(share->cardinality_upd, field))
    {
      DBUG_PRINT("info",
                 ("spider uninitialized column cardinality id=%d", field));
      *tmp_crd = -1;
    }
  }
  if (res)
  {
    res->free_result();
    delete res;
  }
  if (error_num)
  {
    switch (error_num)
    {
    case ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM:
      my_printf_error(
        ER_SPIDER_REMOTE_TABLE_NOT_FOUND_NUM,
        ER_SPIDER_REMOTE_TABLE_NOT_FOUND_STR, MYF(0),
        mysql_share->db_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe(),
        mysql_share->table_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe());
      break;
    case ER_SPIDER_INVALID_REMOTE_TABLE_INFO_NUM:
      my_printf_error(
        ER_SPIDER_INVALID_REMOTE_TABLE_INFO_NUM,
        ER_SPIDER_INVALID_REMOTE_TABLE_INFO_STR, MYF(0),
        mysql_share->db_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe(),
        mysql_share->table_names_str[spider->conn_link_idx[link_idx]].c_ptr_safe());
      break;
    default:
      break;
    }
    goto unlock;
  }
  if (!error_num)
    error_num = ((spider_db_mbase *) conn->db_conn)->reset_lock_wait_timeout();
  else
    ((spider_db_mbase *) conn->db_conn)->reset_lock_wait_timeout();
unlock:
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::simple_action(
  uint simple_action,
  int link_idx
) {
  int error_num;
  SPIDER_CONN *conn = spider->conns[link_idx];
  SPIDER_DB_RESULT *res;
  SPIDER_SHARE *share = spider->share;
  uint pos = spider->conn_link_idx[link_idx];
  spider_string *str = NULL;
  DBUG_ENTER("spider_mbase_handler::simple_action");
  switch (simple_action)
  {
    case SPIDER_SIMPLE_RECORDS:
      DBUG_PRINT("info",("spider simple records"));
      str = &mysql_share->show_records[pos];
      break;
    case SPIDER_SIMPLE_CHECKSUM_TABLE:
      DBUG_PRINT("info",("spider simple checksum_table"));
      str = &spider->result_list.sqls[link_idx];
      str->length(0);
      if (str->reserve(
        SPIDER_SQL_CHECKSUM_TABLE_LEN +
        mysql_share->db_nm_max_length +
        SPIDER_SQL_DOT_LEN +
        mysql_share->table_nm_max_length +
        /* SPIDER_SQL_NAME_QUOTE_LEN */ 4 +
        ((spider->action_flags & T_QUICK) ? SPIDER_SQL_SQL_QUICK_LEN : 0) +
        ((spider->action_flags & T_EXTEND) ? SPIDER_SQL_SQL_EXTENDED_LEN : 0)
      ))
      {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      str->q_append(SPIDER_SQL_CHECKSUM_TABLE_STR,
        SPIDER_SQL_CHECKSUM_TABLE_LEN);
      mysql_share->append_table_name(str, pos);
      if (spider->action_flags & T_QUICK)
      {
        str->q_append(SPIDER_SQL_SQL_QUICK_STR, SPIDER_SQL_SQL_QUICK_LEN);
      }
      if (spider->action_flags & T_EXTEND)
      {
        str->q_append(SPIDER_SQL_SQL_EXTENDED_STR,
          SPIDER_SQL_SQL_EXTENDED_LEN);
      }
      break;
    default:
      DBUG_ASSERT(0);
      DBUG_RETURN(0);
    }
  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    share);
  if (
    (error_num = spider_db_set_names(spider, conn, link_idx)) ||
    (
      spider_db_query(
        conn,
        str->ptr(),
        str->length(),
        -1,
        &spider->need_mons[link_idx]) &&
      (error_num = spider_db_errorno(conn))
    )
  ) {
    if (
      error_num == ER_SPIDER_REMOTE_SERVER_GONE_AWAY_NUM &&
      !conn->disable_reconnect
    ) {
      /* retry */
      if ((error_num = spider_db_ping(spider, conn, link_idx)))
        goto unlock;
      if ((error_num = spider_db_set_names(spider, conn, link_idx)))
        goto unlock;
      spider_conn_set_timeout_from_share(conn, link_idx,
        spider->wide_handler->trx->thd,
        share);
      if (spider_db_query(
        conn,
        str->ptr(),
        str->length(),
        -1,
        &spider->need_mons[link_idx])
      ) {
        error_num= spider_db_errorno(conn);
        goto unlock;
      }
    } else {
      goto unlock;
    }
  }
  error_num= 0;
  st_spider_db_request_key request_key;
  request_key.spider_thread_id = spider->wide_handler->trx->spider_thread_id;
  request_key.query_id = spider->wide_handler->trx->thd->query_id;
  request_key.handler = spider;
  request_key.request_id = 1;
  request_key.next = NULL;
  if (!(res = conn->db_conn->store_result(NULL, &request_key, &error_num)))
  {
    if (error_num)
      goto unlock;
    else if ((error_num = spider_db_errorno(conn)))
      goto unlock;
    else {
      error_num= ER_QUERY_ON_FOREIGN_DATA_SOURCE;
      goto unlock;
    }
  }
  switch (simple_action)
  {
    case SPIDER_SIMPLE_RECORDS:
      DBUG_PRINT("info",("spider simple records"));
      error_num = res->fetch_table_records(1, spider->table_rows);
      break;
    case SPIDER_SIMPLE_CHECKSUM_TABLE:
      DBUG_PRINT("info",("spider simple checksum_table"));
      error_num = res->fetch_table_checksum(spider);
      break;
    default:
      DBUG_ASSERT(0);
      break;
  }
  res->free_result();
  delete res;
unlock:
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::show_records(
  int link_idx
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::show_records");
  error_num = simple_action(SPIDER_SIMPLE_RECORDS, link_idx);
  if (error_num)
  {
    DBUG_PRINT("info", ("spider error_num=%d", error_num));
    DBUG_RETURN(error_num);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::checksum_table(
  int link_idx
) {
  DBUG_ENTER("spider_mbase_handler::checksum_table");
  DBUG_RETURN(simple_action(SPIDER_SIMPLE_CHECKSUM_TABLE, link_idx));
  DBUG_RETURN(0);
}

int spider_mbase_handler::show_last_insert_id(
  int link_idx,
  ulonglong &last_insert_id
) {
  SPIDER_CONN *conn = spider->conns[link_idx];
  DBUG_ENTER("spider_mbase_handler::show_last_insert_id");
  last_insert_id = conn->db_conn->last_insert_id();
  DBUG_RETURN(0);
}

ha_rows spider_mbase_handler::explain_select(
  const key_range *start_key,
  const key_range *end_key,
  int link_idx
) {
  int error_num;
  SPIDER_CONN *conn = spider->conns[link_idx];
  SPIDER_RESULT_LIST *result_list = &spider->result_list;
  spider_string *str = &result_list->sqls[link_idx];
  SPIDER_DB_RESULT *res;
  ha_rows rows;
  spider_db_handler *dbton_hdl = spider->dbton_handler[conn->dbton_id];
  DBUG_ENTER("spider_mbase_handler::explain_select");
  if ((error_num = dbton_hdl->append_explain_select_part(
    start_key, end_key, SPIDER_SQL_TYPE_OTHER_SQL, link_idx)))
  {
    my_errno = error_num;
    DBUG_RETURN(HA_POS_ERROR);
  }

  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    spider->share);
  if (
    (error_num = spider_db_set_names(spider, conn, link_idx)) ||
    (
      spider_db_query(
        conn,
        str->ptr(),
        str->length(),
        -1,
        &spider->need_mons[link_idx]) &&
      (error_num = spider_db_errorno(conn))
    )
  ) {
    if (
      error_num == ER_SPIDER_REMOTE_SERVER_GONE_AWAY_NUM &&
      !conn->disable_reconnect
    ) {
      /* retry */
      if ((error_num = spider_db_ping(spider, conn, link_idx)))
      {
        if (spider->check_error_mode(error_num))
          my_errno = error_num;
        rows= HA_POS_ERROR;
        goto unlock;
      }
      if ((error_num = spider_db_set_names(spider, conn, link_idx)))
      {
        if (spider->check_error_mode(error_num))
          my_errno = error_num;
        rows= HA_POS_ERROR;
        goto unlock;
      }
      spider_conn_set_timeout_from_share(conn, link_idx,
        spider->wide_handler->trx->thd,
        spider->share);
      if (spider_db_query(
        conn,
        str->ptr(),
        str->length(),
        -1,
        &spider->need_mons[link_idx])
      ) {
        error_num = spider_db_errorno(conn);
        if (spider->check_error_mode(error_num))
          my_errno = error_num;
        rows= HA_POS_ERROR;
        goto unlock;
      }
    } else {
      if (spider->check_error_mode(error_num))
        my_errno = error_num;
      rows= HA_POS_ERROR;
      goto unlock;
    }
  }
  st_spider_db_request_key request_key;
  request_key.spider_thread_id = spider->wide_handler->trx->spider_thread_id;
  request_key.query_id = spider->wide_handler->trx->thd->query_id;
  request_key.handler = spider;
  request_key.request_id = 1;
  request_key.next = NULL;
  if (!(res = conn->db_conn->store_result(NULL, &request_key, &error_num)))
  {
    if (error_num || (error_num = spider_db_errorno(conn)))
    {
      if (spider->check_error_mode(error_num))
        my_errno = error_num;
      rows= HA_POS_ERROR;
      goto unlock;
    } else {
      rows= HA_POS_ERROR;
      goto unlock;
    }
  }
  error_num = res->fetch_table_records(
    2,
    rows
  );
  res->free_result();
  delete res;
  if (error_num)
  {
    my_errno = error_num;
    rows= HA_POS_ERROR;
  }
unlock:
  spider_unlock_after_query(conn, 0);
  DBUG_RETURN(rows);
}

int spider_mbase_handler::lock_tables(
  int link_idx
) {
  int error_num;
  SPIDER_CONN *conn = spider->conns[link_idx];
  spider_string *str = &sql;
  DBUG_ENTER("spider_mbase_handler::lock_tables");
  str->length(0);
  if ((error_num = conn->db_conn->append_lock_tables(str)))
  {
    DBUG_RETURN(error_num);
  }
  if (str->length())
  {
    spider_lock_before_query(conn, &spider->need_mons[link_idx]);
    if ((error_num = spider_db_set_names(spider, conn, link_idx)))
      DBUG_RETURN(spider_unlock_after_query(conn, error_num));
    spider_conn_set_timeout_from_share(conn, link_idx,
      spider->wide_handler->trx->thd,
      spider->share);
    if (spider_db_query(
      conn,
      str->ptr(),
      str->length(),
      -1,
      &spider->need_mons[link_idx])
    )
      DBUG_RETURN(spider_unlock_after_query_1(conn));
    spider_unlock_after_query(conn, 0);
  }
  if (!conn->table_locked)
  {
    conn->table_locked = TRUE;
    spider->wide_handler->trx->locked_connections++;
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::unlock_tables(
  int link_idx
) {
  int error_num;
  SPIDER_CONN *conn = spider->conns[link_idx];
  DBUG_ENTER("spider_mbase_handler::unlock_tables");
  if (conn->table_locked)
  {
    spider_string *str = &sql;
    conn->table_locked = FALSE;
    spider->wide_handler->trx->locked_connections--;

    str->length(0);
    if ((error_num = conn->db_conn->append_unlock_tables(str)))
    {
      DBUG_RETURN(error_num);
    }
    if (str->length())
    {
      spider_conn_set_timeout_from_share(conn, link_idx,
        spider->wide_handler->trx->thd,
        spider->share);
      DBUG_RETURN(spider_db_query_with_lock(
                    conn, str->ptr(), str->length(),
                    &spider->need_mons[link_idx]));
    }
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::disable_keys(
  SPIDER_CONN *conn,
  int link_idx
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  spider_string *str = &spider->result_list.sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::disable_keys");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(0);
  if ((error_num= append_disable_keys_part(link_idx)))
  {
    DBUG_RETURN(error_num);
  }
  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  if ((error_num = spider_db_set_names(spider, conn, link_idx)))
    goto unlock;
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    share);
  if (spider_db_query(
    conn,
    str->ptr(),
    str->length(),
    -1,
    &spider->need_mons[link_idx])
  )
    error_num = spider_db_errorno(conn);
unlock:
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::enable_keys(
  SPIDER_CONN *conn,
  int link_idx
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  spider_string *str = &spider->result_list.sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::enable_keys");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(0);
  if ((error_num= append_enable_keys_part(link_idx)))
  {
    DBUG_RETURN(error_num);
  }
  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  if ((error_num = spider_db_set_names(spider, conn, link_idx)))
    goto unlock;
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    share);
  if (spider_db_query(
    conn,
    str->ptr(),
    str->length(),
    -1,
    &spider->need_mons[link_idx])
  )
    error_num = spider_db_errorno(conn);
unlock:
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::check_table(
  SPIDER_CONN *conn,
  int link_idx,
  HA_CHECK_OPT* check_opt
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  spider_string *str = &spider->result_list.sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::check_table");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(0);
  if ((error_num= append_check_table_part(link_idx, check_opt)))
  {
    DBUG_RETURN(error_num);
  }
  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  if ((error_num = spider_db_set_names(spider, conn, link_idx)))
    goto unlock;
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    share);
  if (spider_db_query(
    conn,
    str->ptr(),
    str->length(),
    -1,
    &spider->need_mons[link_idx])
  ) {
    error_num = spider_db_errorno(conn);
  }
unlock:
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::repair_table(
  SPIDER_CONN *conn,
  int link_idx,
  HA_CHECK_OPT* check_opt
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  spider_string *str = &spider->result_list.sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::repair_table");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(0);
  if ((error_num= append_repair_table_part(link_idx, check_opt)))
  {
    DBUG_RETURN(error_num);
  }
  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  if ((error_num = spider_db_set_names(spider, conn, link_idx)))
    goto unlock;
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    share);
  if (spider_db_query(
    conn,
    str->ptr(),
    str->length(),
    -1,
    &spider->need_mons[link_idx])
  ) {
    error_num = spider_db_errorno(conn);
  }
unlock:
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::analyze_table(
  SPIDER_CONN *conn,
  int link_idx
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  spider_string *str = &spider->result_list.sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::analyze_table");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(0);
  if ((error_num= append_analyze_table_part(link_idx)))
  {
    DBUG_RETURN(error_num);
  }
  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
    error_num = spider_db_set_names(spider, conn, link_idx);
    if (!error_num)
    {
      spider_conn_set_timeout_from_share(conn, link_idx,
                                         spider->wide_handler->trx->thd,
                                         share);
      if (spider_db_query(conn, str->ptr(), str->length(), -1,
                          &spider->need_mons[link_idx]))
        error_num = spider_db_errorno(conn);
    }
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::optimize_table(
  SPIDER_CONN *conn,
  int link_idx
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  spider_string *str = &spider->result_list.sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::optimize_table");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(0);
  if ((error_num= append_optimize_table_part(link_idx)))
  {
    DBUG_RETURN(error_num);
  }
  spider_lock_before_query(conn, &spider->need_mons[link_idx]);
  if ((error_num = spider_db_set_names(spider, conn, link_idx)))
    goto unlock;
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    share);
  if (spider_db_query(
    conn,
    str->ptr(),
    str->length(),
    -1,
    &spider->need_mons[link_idx])
  ) {
    error_num = spider_db_errorno(conn);
  }
unlock:
  DBUG_RETURN(spider_unlock_after_query(conn, error_num));
}

int spider_mbase_handler::flush_tables(
  SPIDER_CONN *conn,
  int link_idx,
  bool lock
) {
  int error_num;
  SPIDER_SHARE *share = spider->share;
  spider_string *str = &spider->result_list.sqls[link_idx];
  DBUG_ENTER("spider_mbase_handler::flush_tables");
  DBUG_PRINT("info",("spider this=%p", this));
  str->length(0);
  if ((error_num= append_flush_tables_part(link_idx, lock)))
  {
    DBUG_RETURN(error_num);
  }
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    share);
  DBUG_RETURN(spider_db_query_with_lock(
                conn, str->ptr(), str->length(), &spider->need_mons[link_idx]));
}

int spider_mbase_handler::flush_logs(
  SPIDER_CONN *conn,
  int link_idx
) {
  SPIDER_SHARE *share = spider->share;
  DBUG_ENTER("spider_mbase_handler::flush_logs");
  DBUG_PRINT("info",("spider this=%p", this));
  spider_conn_set_timeout_from_share(conn, link_idx,
    spider->wide_handler->trx->thd,
    share);
  DBUG_RETURN(spider_db_query_with_lock(
                conn, SPIDER_SQL_FLUSH_LOGS_STR,
                SPIDER_SQL_FLUSH_LOGS_LEN, &spider->need_mons[link_idx]));
}

int spider_mbase_handler::sync_from_clone_source(
  spider_db_handler *dbton_hdl
) {
  DBUG_ENTER("spider_mbase_handler::sync_from_clone_source");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(0);
}

void spider_mbase_handler::minimum_select_bitmap_create()
{
  TABLE *table = spider->get_table();
  Field **field_p;
  DBUG_ENTER("spider_mbase_handler::minimum_select_bitmap_create");
  DBUG_PRINT("info",("spider this=%p", this));
  memset(minimum_select_bitmap, 0, my_bitmap_buffer_size(table->read_set));
  if (
    spider->use_index_merge ||
    spider->is_clone
  ) {
    /* need preparing for cmp_ref */
    TABLE_SHARE *table_share = table->s;
    if (
      table_share->primary_key == MAX_KEY
    ) {
      /* need all columns */
      memset(minimum_select_bitmap, 0xFF, my_bitmap_buffer_size(table->read_set));
      DBUG_VOID_RETURN;
    } else {
      /* need primary key columns */
      uint roop_count;
      KEY *key_info;
      KEY_PART_INFO *key_part;
      Field *field;
      key_info = &table_share->key_info[table_share->primary_key];
      key_part = key_info->key_part;
      for (roop_count = 0;
        roop_count < spider_user_defined_key_parts(key_info);
        roop_count++)
      {
        field = key_part[roop_count].field;
        spider_set_bit(minimum_select_bitmap, field->field_index);
      }
    }
  }
  DBUG_PRINT("info",("spider searched_bitmap=%p",
    spider->wide_handler->searched_bitmap));
  for (field_p = table->field; *field_p; field_p++)
  {
    uint field_index = (*field_p)->field_index;
    DBUG_PRINT("info",("spider field_index=%u", field_index));
    DBUG_PRINT("info",("spider ft_discard_bitmap=%s",
      spider_bit_is_set(spider->wide_handler->ft_discard_bitmap, field_index) ?
        "TRUE" : "FALSE"));
    DBUG_PRINT("info",("spider searched_bitmap=%s",
      spider_bit_is_set(spider->wide_handler->searched_bitmap, field_index) ?
        "TRUE" : "FALSE"));
    DBUG_PRINT("info",("spider read_set=%s",
      bitmap_is_set(table->read_set, field_index) ?
        "TRUE" : "FALSE"));
    DBUG_PRINT("info",("spider write_set=%s",
      bitmap_is_set(table->write_set, field_index) ?
        "TRUE" : "FALSE"));
    if (
      spider_bit_is_set(spider->wide_handler->ft_discard_bitmap, field_index) &&
      (
        spider_bit_is_set(spider->wide_handler->searched_bitmap, field_index) ||
        bitmap_is_set(table->read_set, field_index) ||
        bitmap_is_set(table->write_set, field_index)
      )
    ) {
      spider_set_bit(minimum_select_bitmap, field_index);
    }
  }
  DBUG_VOID_RETURN;
}

bool spider_mbase_handler::minimum_select_bit_is_set(
  uint field_index
) {
  DBUG_ENTER("spider_mbase_handler::minimum_select_bit_is_set");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_PRINT("info",("spider field_index=%u", field_index));
  DBUG_PRINT("info",("spider minimum_select_bitmap=%s",
    spider_bit_is_set(minimum_select_bitmap, field_index) ?
      "TRUE" : "FALSE"));
  DBUG_RETURN(spider_bit_is_set(minimum_select_bitmap, field_index));
}

void spider_mbase_handler::copy_minimum_select_bitmap(
  uchar *bitmap
) {
  int roop_count;
  TABLE *table = spider->get_table();
  DBUG_ENTER("spider_mbase_handler::copy_minimum_select_bitmap");
  for (roop_count = 0;
    roop_count < (int) ((table->s->fields + 7) / 8);
    roop_count++)
  {
    bitmap[roop_count] =
      minimum_select_bitmap[roop_count];
    DBUG_PRINT("info",("spider roop_count=%d", roop_count));
    DBUG_PRINT("info",("spider bitmap=%d",
      bitmap[roop_count]));
  }
  DBUG_VOID_RETURN;
}

int spider_mbase_handler::init_union_table_name_pos()
{
  DBUG_ENTER("spider_mbase_handler::init_union_table_name_pos");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!union_table_name_pos_first)
  {
    if (!spider_bulk_malloc(spider_current_trx, SPD_MID_MBASE_HANDLER_INIT_UNION_TABLE_NAME_POS_1, MYF(MY_WME),
      &union_table_name_pos_first, (uint) (sizeof(SPIDER_INT_HLD)),
      NullS)
    ) {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    union_table_name_pos_first->next = NULL;
  }
  union_table_name_pos_current = union_table_name_pos_first;
  union_table_name_pos_current->tgt_num = 0;
  DBUG_RETURN(0);
}

int spider_mbase_handler::set_union_table_name_pos()
{
  DBUG_ENTER("spider_mbase_handler::set_union_table_name_pos");
  DBUG_PRINT("info",("spider this=%p", this));
  if (union_table_name_pos_current->tgt_num >= SPIDER_INT_HLD_TGT_SIZE)
  {
    if (!union_table_name_pos_current->next)
    {
      if (!spider_bulk_malloc(spider_current_trx, SPD_MID_MBASE_HANDLER_SET_UNION_TABLE_NAME_POS_1, MYF(MY_WME),
        &union_table_name_pos_current->next, (uint) (sizeof(SPIDER_INT_HLD)),
        NullS)
      ) {
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      }
      union_table_name_pos_current->next->next = NULL;
    }
    union_table_name_pos_current = union_table_name_pos_current->next;
    union_table_name_pos_current->tgt_num = 0;
  }
  union_table_name_pos_current->tgt[union_table_name_pos_current->tgt_num] =
    table_name_pos;
  ++union_table_name_pos_current->tgt_num;
  DBUG_RETURN(0);
}

int spider_mbase_handler::reset_union_table_name(
  spider_string *str,
  int link_idx,
  ulong sql_type
) {
  DBUG_ENTER("spider_mbase_handler::reset_union_table_name");
  DBUG_PRINT("info",("spider this=%p", this));
  if (!union_table_name_pos_current)
    DBUG_RETURN(0);

  SPIDER_INT_HLD *tmp_pos = union_table_name_pos_first;
  uint cur_num, pos_backup = str->length();
  while(TRUE)
  {
    for (cur_num = 0; cur_num < tmp_pos->tgt_num; ++cur_num)
    {
      str->length(tmp_pos->tgt[cur_num]);
      append_table_name_with_adjusting(str, link_idx, sql_type);
    }
    if (tmp_pos == union_table_name_pos_current)
      break;
    tmp_pos = tmp_pos->next;
  }
  str->length(pos_backup);
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_from_and_tables_part(
  spider_fields *fields,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  SPIDER_TABLE_HOLDER *table_holder;
  TABLE_LIST *table_list;
  DBUG_ENTER("spider_mbase_handler::append_from_and_tables_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  table_holder = fields->get_first_table_holder();
  table_list = table_holder->table->pos_in_table_list;
  error_num = spider_db_mbase_utility->append_from_and_tables(
    table_holder->spider, fields, str,
    table_list, fields->get_table_count());
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_where_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_where_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = spider_db_mbase_utility->append_where(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_having_part(
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_having_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = spider_db_mbase_utility->append_having(str);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_item_type_part(
  Item *item,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_item_type_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = spider_db_print_item_type(item, NULL, spider, str,
    alias, alias_length, dbton_id, use_fields, fields);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_list_item_select_part(
  List<Item> *select,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields,
  ulong sql_type,
  int n_aux
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_list_item_select_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_list_item_select(select, str, alias, alias_length,
                                      use_fields, fields, n_aux);
  DBUG_RETURN(error_num);
}

int spider_mbase_handler::append_list_item_select(
  List<Item> *select,
  spider_string *str,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields,
  int n_aux
) {
  int error_num;
  uint32 length, begin;
  List_iterator_fast<Item> it(*select);
  Item *item;
  const char *item_name;
  DBUG_ENTER("spider_mbase_handler::append_list_item_select");
  DBUG_PRINT("info",("spider this=%p", this));
  begin = str->length();
  while ((item = it++))
  {
    fields->get_next_field_ptr();
    if (n_aux-- > 0)
      continue;
    if ((error_num = spider_db_print_item_type(item, NULL, spider, str,
      alias, alias_length, dbton_id, use_fields, fields)))
    {
      DBUG_RETURN(error_num);
    }
    item_name = SPIDER_item_name_str(item);
    length = SPIDER_item_name_length(item);
    if (str->reserve(
      SPIDER_SQL_COMMA_LEN + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 +
      SPIDER_SQL_SPACE_LEN + length
    ))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_SPACE_STR, SPIDER_SQL_SPACE_LEN);
    if ((error_num = spider_db_mbase_utility->append_escaped_name(str,
      item_name, length)))
    {
      DBUG_RETURN(error_num);
    }
    str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  if (begin == str->length())
  {
    /* no columns */
    if (str->reserve(SPIDER_SQL_ONE_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    str->q_append(SPIDER_SQL_ONE_STR, SPIDER_SQL_ONE_LEN);
  } else {
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_group_by_part(
  ORDER *order,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_group_by_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_group_by(order, str, alias, alias_length,
    use_fields, fields);
  DBUG_RETURN(error_num);
}

/*
  Append the GROUP BY part.

  Only used by the group by handler for query construction.
*/
int spider_mbase_handler::append_group_by(
  ORDER *order,
  spider_string *str,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_group_by");
  DBUG_PRINT("info",("spider this=%p", this));
  if (order)
  {
    if (str->reserve(SPIDER_SQL_GROUP_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_GROUP_STR, SPIDER_SQL_GROUP_LEN);
    for (; order; order = order->next)
    {
      /*
        This is not expected to happen, as NULL check was performed
        at the creation of the group by handler, and any NULL item_ptr
        would have resulted in the gbh not being created.
      */
      if (!order->item_ptr)
        DBUG_RETURN(ER_INTERNAL_ERROR);
      if ((error_num = spider_db_print_item_type(order->item_ptr, NULL, spider,
        str, alias, alias_length, dbton_id, use_fields, fields)))
      {
        DBUG_RETURN(error_num);
      }
      if (str->reserve(SPIDER_SQL_COMMA_LEN))
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
      str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_handler::append_order_by_part(
  ORDER *order,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields,
  ulong sql_type
) {
  int error_num;
  spider_string *str;
  DBUG_ENTER("spider_mbase_handler::append_order_by_part");
  DBUG_PRINT("info",("spider this=%p", this));
  switch (sql_type)
  {
    case SPIDER_SQL_TYPE_SELECT_SQL:
      str = &sql;
      break;
    default:
      DBUG_RETURN(0);
  }
  error_num = append_order_by(order, str, alias, alias_length,
    use_fields, fields);
  DBUG_RETURN(error_num);
}

/*
  Append the ORDER BY part.

  Only used by the group by handler for query construction.
*/
int spider_mbase_handler::append_order_by(
  ORDER *order,
  spider_string *str,
  const char *alias,
  uint alias_length,
  bool use_fields,
  spider_fields *fields
) {
  int error_num;
  DBUG_ENTER("spider_mbase_handler::append_order_by");
  DBUG_PRINT("info",("spider this=%p", this));
  if (order)
  {
    if (str->reserve(SPIDER_SQL_ORDER_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    str->q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
    for (; order; order = order->next)
    {
      /*
        This is not expected to happen, as NULL check was performed
        at the creation of the group by handler, and any NULL item_ptr
        would have resulted in the gbh not being created.
      */
      if (!order->item_ptr)
        DBUG_RETURN(ER_INTERNAL_ERROR);
      if ((error_num = spider_db_print_item_type(order->item_ptr, NULL, spider,
        str, alias, alias_length, dbton_id, use_fields, fields)))
      {
        DBUG_RETURN(error_num);
      }
      if (SPIDER_order_direction_is_asc(order))
      {
        if (str->reserve(SPIDER_SQL_COMMA_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      } else {
        if (str->reserve(SPIDER_SQL_COMMA_LEN + SPIDER_SQL_DESC_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        str->q_append(SPIDER_SQL_DESC_STR, SPIDER_SQL_DESC_LEN);
        str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
      }
    }
    str->length(str->length() - SPIDER_SQL_COMMA_LEN);
  }
  DBUG_RETURN(0);
}

bool spider_mbase_handler::check_direct_update(
  st_select_lex *select_lex,
  longlong select_limit,
  longlong offset_limit
) {
  DBUG_ENTER("spider_mbase_handler::check_direct_update");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(FALSE);
}

bool spider_mbase_handler::check_direct_delete(
  st_select_lex *select_lex,
  longlong select_limit,
  longlong offset_limit
) {
  DBUG_ENTER("spider_mbase_handler::check_direct_delete");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_RETURN(FALSE);
}

spider_mbase_copy_table::spider_mbase_copy_table(
  spider_mbase_share *db_share
) : spider_db_copy_table(
  db_share
),
  mysql_share(db_share)
{
  DBUG_ENTER("spider_mbase_copy_table::spider_mbase_copy_table");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mysql_copy_table::spider_mysql_copy_table(
  spider_mbase_share *db_share
) : spider_mbase_copy_table(
  db_share
) {
  DBUG_ENTER("spider_mysql_copy_table::spider_mysql_copy_table");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mariadb_copy_table::spider_mariadb_copy_table(
  spider_mbase_share *db_share
) : spider_mbase_copy_table(
  db_share
) {
  DBUG_ENTER("spider_mariadb_copy_table::spider_mariadb_copy_table");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mbase_copy_table::~spider_mbase_copy_table()
{
  DBUG_ENTER("spider_mbase_copy_table::~spider_mbase_copy_table");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mysql_copy_table::~spider_mysql_copy_table()
{
  DBUG_ENTER("spider_mysql_copy_table::~spider_mysql_copy_table");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

spider_mariadb_copy_table::~spider_mariadb_copy_table()
{
  DBUG_ENTER("spider_mariadb_copy_table::~spider_mariadb_copy_table");
  DBUG_PRINT("info",("spider this=%p", this));
  DBUG_VOID_RETURN;
}

int spider_mbase_copy_table::init()
{
  DBUG_ENTER("spider_mbase_copy_table::init");
  DBUG_PRINT("info",("spider this=%p", this));
  sql.init_calc_mem(SPD_MID_MBASE_COPY_TABLE_INIT_1);
  DBUG_RETURN(0);
}

void spider_mbase_copy_table::set_sql_charset(
  CHARSET_INFO *cs
) {
  DBUG_ENTER("spider_mbase_copy_table::set_sql_charset");
  DBUG_PRINT("info",("spider this=%p", this));
  sql.set_charset(cs);
  DBUG_VOID_RETURN;
}

int spider_mbase_copy_table::append_select_str()
{
  DBUG_ENTER("spider_mbase_copy_table::append_select_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql.reserve(SPIDER_SQL_SELECT_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_SELECT_STR, SPIDER_SQL_SELECT_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_insert_str(
  int insert_flg
) {
  DBUG_ENTER("spider_mbase_copy_table::append_insert_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if (insert_flg & SPIDER_DB_INSERT_REPLACE)
  {
    if (sql.reserve(SPIDER_SQL_REPLACE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_REPLACE_STR, SPIDER_SQL_REPLACE_LEN);
  } else {
    if (sql.reserve(SPIDER_SQL_INSERT_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_INSERT_STR, SPIDER_SQL_INSERT_LEN);
  }
  if (insert_flg & SPIDER_DB_INSERT_LOW_PRIORITY)
  {
    if (sql.reserve(SPIDER_SQL_LOW_PRIORITY_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_LOW_PRIORITY_STR, SPIDER_SQL_LOW_PRIORITY_LEN);
  }
  else if (insert_flg & SPIDER_DB_INSERT_HIGH_PRIORITY)
  {
    if (sql.reserve(SPIDER_SQL_HIGH_PRIORITY_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_HIGH_PRIORITY_STR, SPIDER_SQL_HIGH_PRIORITY_LEN);
  }
  if (insert_flg & SPIDER_DB_INSERT_IGNORE)
  {
    if (sql.reserve(SPIDER_SQL_SQL_IGNORE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_SQL_IGNORE_STR, SPIDER_SQL_SQL_IGNORE_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_table_columns(
  TABLE_SHARE *table_share
) {
  int error_num;
  Field **field;
  DBUG_ENTER("spider_mbase_copy_table::append_table_columns");
  DBUG_PRINT("info",("spider this=%p", this));
  for (field = table_share->field; *field; field++)
  {
    if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    if ((error_num = spider_db_append_name_with_quote_str(&sql,
      (*field)->field_name, dbton_id)))
      DBUG_RETURN(error_num);
    if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN + SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
    sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  }
  sql.length(sql.length() - SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_from_str()
{
  DBUG_ENTER("spider_mbase_copy_table::append_from_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql.reserve(SPIDER_SQL_FROM_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_FROM_STR, SPIDER_SQL_FROM_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_table_name(
  int link_idx
) {
  int error_num;
  DBUG_ENTER("spider_mbase_copy_table::append_table_name");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = mysql_share->append_table_name(&sql, link_idx);
  DBUG_RETURN(error_num);
}

void spider_mbase_copy_table::set_sql_pos()
{
  DBUG_ENTER("spider_mbase_copy_table::set_sql_pos");
  DBUG_PRINT("info",("spider this=%p", this));
  pos = sql.length();
  DBUG_VOID_RETURN;
}

void spider_mbase_copy_table::set_sql_to_pos()
{
  DBUG_ENTER("spider_mbase_copy_table::set_sql_to_pos");
  DBUG_PRINT("info",("spider this=%p", this));
  sql.length(pos);
  DBUG_VOID_RETURN;
}

int spider_mbase_copy_table::append_copy_where(
  spider_db_copy_table *source_ct,
  KEY *key_info,
  ulong *last_row_pos,
  ulong *last_lengths
) {
  int error_num, roop_count, roop_count2;
  DBUG_ENTER("spider_mbase_copy_table::append_copy_where");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql.reserve(SPIDER_SQL_WHERE_LEN + SPIDER_SQL_OPEN_PAREN_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  sql.q_append(SPIDER_SQL_WHERE_STR, SPIDER_SQL_WHERE_LEN);
  sql.q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  Field *field;
  KEY_PART_INFO *key_part = key_info->key_part;
  for (roop_count = spider_user_defined_key_parts(key_info) - 1;
    roop_count >= 0; roop_count--)
  {
    for (roop_count2 = 0; roop_count2 < roop_count; roop_count2++)
    {
      field = key_part[roop_count2].field;
      if ((error_num = copy_key_row(source_ct,
        field, &last_row_pos[field->field_index],
        &last_lengths[field->field_index],
        SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN)))
      {
        DBUG_RETURN(error_num);
      }
    }
    field = key_part[roop_count2].field;
    if ((error_num = copy_key_row(source_ct,
      field, &last_row_pos[field->field_index],
      &last_lengths[field->field_index],
      SPIDER_SQL_GT_STR, SPIDER_SQL_GT_LEN)))
    {
      DBUG_RETURN(error_num);
    }
    sql.length(sql.length() - SPIDER_SQL_AND_LEN);
    if (sql.reserve(SPIDER_SQL_CLOSE_PAREN_LEN +
      SPIDER_SQL_OR_LEN + SPIDER_SQL_OPEN_PAREN_LEN))
    {
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }
    sql.q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
    sql.q_append(SPIDER_SQL_OR_STR, SPIDER_SQL_OR_LEN);
    sql.q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  }
  sql.length(sql.length() - SPIDER_SQL_OR_LEN - SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_key_order_str(
  KEY *key_info,
  int start_pos,
  bool desc_flg
) {
  int length, error_num;
  KEY_PART_INFO *key_part;
  Field *field;
  DBUG_ENTER("spider_mbase_copy_table::append_key_order_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if ((int) spider_user_defined_key_parts(key_info) > start_pos)
  {
    if (sql.reserve(SPIDER_SQL_ORDER_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_ORDER_STR, SPIDER_SQL_ORDER_LEN);
    if (desc_flg == TRUE)
    {
      for (
        key_part = key_info->key_part + start_pos,
        length = 0;
        length + start_pos < (int) spider_user_defined_key_parts(key_info);
        key_part++,
        length++
      ) {
        field = key_part->field;
        if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
        if ((error_num = spider_db_append_name_with_quote_str(&sql,
          field->field_name, dbton_id)))
          DBUG_RETURN(error_num);
        if (key_part->key_part_flag & HA_REVERSE_SORT)
        {
          if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN + SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
          sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
        } else {
          if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN + SPIDER_SQL_DESC_LEN +
            SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
          sql.q_append(SPIDER_SQL_DESC_STR, SPIDER_SQL_DESC_LEN);
          sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
        }
      }
    } else {
      for (
        key_part = key_info->key_part + start_pos,
        length = 0;
        length + start_pos < (int) spider_user_defined_key_parts(key_info);
        key_part++,
        length++
      ) {
        field = key_part->field;
        if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN))
          DBUG_RETURN(HA_ERR_OUT_OF_MEM);
        sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
        if ((error_num = spider_db_append_name_with_quote_str(&sql,
          field->field_name, dbton_id)))
          DBUG_RETURN(error_num);
        if (key_part->key_part_flag & HA_REVERSE_SORT)
        {
          if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN + SPIDER_SQL_DESC_LEN +
            SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
          sql.q_append(SPIDER_SQL_DESC_STR, SPIDER_SQL_DESC_LEN);
          sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
        } else {
          if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN + SPIDER_SQL_COMMA_LEN))
            DBUG_RETURN(HA_ERR_OUT_OF_MEM);
          sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
          sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
        }
      }
    }
    sql.length(sql.length() - SPIDER_SQL_COMMA_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_limit(
  longlong offset,
  longlong limit
) {
  char buf[SPIDER_LONGLONG_LEN + 1];
  uint32 length;
  DBUG_ENTER("spider_mbase_copy_table::append_limit");
  DBUG_PRINT("info",("spider this=%p", this));
  if (offset || limit < 9223372036854775807LL)
  {
    if (sql.reserve(SPIDER_SQL_LIMIT_LEN + SPIDER_SQL_COMMA_LEN +
      ((SPIDER_LONGLONG_LEN) * 2)))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_LIMIT_STR, SPIDER_SQL_LIMIT_LEN);
    if (offset)
    {
      length = (uint32) (my_charset_bin.longlong10_to_str)(
        buf, SPIDER_LONGLONG_LEN + 1, -10, offset);
      sql.q_append(buf, length);
      sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
    }
    length = (uint32) (my_charset_bin.longlong10_to_str)(
      buf, SPIDER_LONGLONG_LEN + 1, -10, limit);
    sql.q_append(buf, length);
  }
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_into_str()
{
  DBUG_ENTER("spider_mbase_copy_table::append_into_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql.reserve(SPIDER_SQL_INTO_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_INTO_STR, SPIDER_SQL_INTO_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_open_paren_str()
{
  DBUG_ENTER("spider_mbase_copy_table::append_open_paren_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql.reserve(SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_values_str()
{
  DBUG_ENTER("spider_mbase_copy_table::append_values_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql.reserve(SPIDER_SQL_CLOSE_PAREN_LEN + SPIDER_SQL_VALUES_LEN +
    SPIDER_SQL_OPEN_PAREN_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  sql.q_append(SPIDER_SQL_VALUES_STR, SPIDER_SQL_VALUES_LEN);
  sql.q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_select_lock_str(
  int lock_mode
) {
  DBUG_ENTER("spider_mbase_copy_table::append_select_lock_str");
  DBUG_PRINT("info",("spider this=%p", this));
  if (lock_mode == SPIDER_LOCK_MODE_EXCLUSIVE)
  {
    if (sql.reserve(SPIDER_SQL_FOR_UPDATE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_FOR_UPDATE_STR, SPIDER_SQL_FOR_UPDATE_LEN);
  } else if (lock_mode == SPIDER_LOCK_MODE_SHARED)
  {
    if (sql.reserve(SPIDER_SQL_SHARED_LOCK_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_SHARED_LOCK_STR, SPIDER_SQL_SHARED_LOCK_LEN);
  }
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::exec_query(
  SPIDER_CONN *conn,
  int quick_mode,
  int *need_mon
) {
  int error_num;
  DBUG_ENTER("spider_mbase_copy_table::exec_query");
  DBUG_PRINT("info",("spider this=%p", this));
  error_num = spider_db_query(conn, sql.ptr(), sql.length(), quick_mode,
    need_mon);
  DBUG_RETURN(error_num);
}

int spider_mbase_copy_table::copy_key_row(
  spider_db_copy_table *source_ct,
  Field *field,
  ulong *row_pos,
  ulong *length,
  const char *joint_str,
  const int joint_length
) {
  int error_num;
  spider_string *source_str = &((spider_mbase_copy_table *) source_ct)->sql;
  DBUG_ENTER("spider_mbase_copy_table::copy_key_row");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  if ((error_num = spider_db_append_name_with_quote_str(&sql,
    field->field_name, dbton_id)))
    DBUG_RETURN(error_num);
  if (sql.reserve(SPIDER_SQL_NAME_QUOTE_LEN + joint_length + *length +
    SPIDER_SQL_AND_LEN))
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  sql.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN);
  sql.q_append(joint_str, joint_length);
  sql.q_append(source_str->ptr() + *row_pos, *length);
  sql.q_append(SPIDER_SQL_AND_STR, SPIDER_SQL_AND_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::copy_row(
  Field *field,
  SPIDER_DB_ROW *row
) {
  int error_num;
  DBUG_ENTER("spider_mbase_copy_table::copy_row");
  DBUG_PRINT("info",("spider this=%p", this));
  if (row->is_null())
  {
    if (sql.reserve(SPIDER_SQL_NULL_LEN + SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_NULL_STR, SPIDER_SQL_NULL_LEN);
  } else if (field->str_needs_quotes())
  {
    if (sql.reserve(SPIDER_SQL_VALUE_QUOTE_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
    if ((error_num = row->append_escaped_to_str(&sql,
      dbton_id)))
      DBUG_RETURN(error_num);
    if (sql.reserve(SPIDER_SQL_VALUE_QUOTE_LEN + SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    sql.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN);
  } else {
    if ((error_num = row->append_to_str(&sql)))
      DBUG_RETURN(error_num);
    if (sql.reserve(SPIDER_SQL_COMMA_LEN))
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::copy_rows(
  TABLE *table,
  SPIDER_DB_ROW *row,
  ulong **last_row_pos,
  ulong **last_lengths
) {
  int error_num;
  Field **field;
  ulong *lengths2, *row_pos2;
  DBUG_ENTER("spider_mbase_copy_table::copy_rows");
  DBUG_PRINT("info",("spider this=%p", this));
  row_pos2 = *last_row_pos;
  lengths2 = *last_lengths;

  for (
    field = table->field;
    *field;
    field++,
    lengths2++
  ) {
    *row_pos2 = sql.length();
    if ((error_num =
      copy_row(*field, row)))
      DBUG_RETURN(error_num);
    *lengths2 = sql.length() - *row_pos2 - SPIDER_SQL_COMMA_LEN;
    row->next();
    row_pos2++;
  }
  sql.length(sql.length() - SPIDER_SQL_COMMA_LEN);
  if (sql.reserve(SPIDER_SQL_CLOSE_PAREN_LEN +
    SPIDER_SQL_COMMA_LEN + SPIDER_SQL_OPEN_PAREN_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  sql.q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  sql.q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::copy_rows(
  TABLE *table,
  SPIDER_DB_ROW *row
) {
  int error_num;
  Field **field;
  DBUG_ENTER("spider_mbase_copy_table::copy_rows");
  DBUG_PRINT("info",("spider this=%p", this));
  for (
    field = table->field;
    *field;
    field++
  ) {
    if ((error_num =
      copy_row(*field, row)))
      DBUG_RETURN(error_num);
    row->next();
  }
  sql.length(sql.length() - SPIDER_SQL_COMMA_LEN);
  if (sql.reserve(SPIDER_SQL_CLOSE_PAREN_LEN +
    SPIDER_SQL_COMMA_LEN + SPIDER_SQL_OPEN_PAREN_LEN))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  sql.q_append(SPIDER_SQL_CLOSE_PAREN_STR, SPIDER_SQL_CLOSE_PAREN_LEN);
  sql.q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN);
  sql.q_append(SPIDER_SQL_OPEN_PAREN_STR, SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::append_insert_terminator()
{
  DBUG_ENTER("spider_mbase_copy_table::append_insert_terminator");
  DBUG_PRINT("info",("spider this=%p", this));
  sql.length(sql.length() - SPIDER_SQL_COMMA_LEN - SPIDER_SQL_OPEN_PAREN_LEN);
  DBUG_RETURN(0);
}

int spider_mbase_copy_table::copy_insert_values(
  spider_db_copy_table *source_ct
) {
  spider_mbase_copy_table *tmp_ct = (spider_mbase_copy_table *) source_ct;
  spider_string *source_str = &tmp_ct->sql;
  int values_length = source_str->length() - tmp_ct->pos;
  const char *values_ptr = source_str->ptr() + tmp_ct->pos;
  DBUG_ENTER("spider_mbase_copy_table::copy_insert_values");
  DBUG_PRINT("info",("spider this=%p", this));
  if (sql.reserve(values_length))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  sql.q_append(values_ptr, values_length);
  DBUG_RETURN(0);
}
